nodes.json Schema Reference
NORTHSTAR SHOW SYSTEMS
nodes.json Schema Reference
Complete field-level schema for the show configuration file
v1.0 — May 2026
nodes.json Schema Reference
The nodes.json file defines the entire show: buildings, nodes, channels, groups, sequences, and schedules. It is authored in Compose (the show designer app), uploaded to HelmOS via POST /api/config, and stored at C:\ProgramData\Helm\nodes.json in production. HelmOS never writes to this file directly except through the validated upload endpoint.
Top-level structure
| Section | Type | Description |
|---|---|---|
| project | Object | Show metadata: name, description, modifiedAt (ISO-8601) |
| network | Object | Network config: ssid, subnet, nucIp, dashboardPort |
| buildings[] | Array | Logical groupings of nodes (rooms, zones, floors) |
| nodes[] | Array | Individual Polaris field nodes with channel configs |
| groups[] | Array | Named collections of channels across nodes |
| sequences[] | Array | Ordered step lists with absolute timing |
| schedules[] | Array | Time-based automation rules |
buildings
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| name | String | Display name |
| description | String | Optional description |
| color | String | Hex color (#RRGGBB) used as the building’s band color in Cuemaster |
| ipRangeStart | String | Starting IP for nodes in this building (informational) |
nodes
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier (duplicates rejected) |
| name | String | Display name |
| ip | String | Static or DHCP IP address on TrueNorth |
| type | Enum | audio | video | gpio | mixed |
| building | String | Building name (must match a buildings[].name) |
| zone | String | Sub-location within building |
| description | String | Optional description |
| channels[] | Array | Channel definitions (see below) |
channels
| Field | Type | Description |
|---|---|---|
| ch | Integer | Channel number (1-based) |
| pin | Integer | Physical GPIO pin on the Polaris node |
| type | Integer | 0 = active LOW, 1 = active HIGH |
| deviceType | Enum | PEMENOL | NEUMI | GPIO | Relay |
| name | String | Human-readable channel name |
| mode | Enum | pulse | latch | timed |
| pulseMs | Integer | Duration for pulse mode (milliseconds) |
| cooldownMs | Integer | Minimum time between triggers (milliseconds) |
| enabled | Boolean | Whether this channel is active |
groups
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| name | String | Display name |
| description | String | Optional description |
| channels[] | Array | Array of {nodeId, ch} references. Each must resolve to a real node and channel. |
sequences
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| name | String | Display name. A sequence named exactly "boot" is auto-fired on SHOW_START. |
| description | String | Optional description |
| loopCount | Integer | 0 = infinite loop, otherwise exact repeat count |
| steps[] | Array | Ordered list of timed actions (see below) |
steps
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier within the sequence |
| targetType | Enum | channel | group |
| nodeId | String | Target node ID (when targetType = channel) |
| ch | Integer | Target channel (when targetType = channel) |
| groupId | String | Target group ID (when targetType = group) |
| delayMs | Integer | ABSOLUTE delay from sequence start (not relative to previous step) |
| action | Enum | trigger | latchOn | latchOff |
| durationOverride | Integer | Optional override for pulse duration (milliseconds) |
Important:delayMs is absolute from sequence start, not relative to the previous step. A step with delayMs: 5000 fires 5 seconds after the sequence begins regardless of when earlier steps fired.
Important:Group steps fan out in parallel — one HTTP call per member channel, not serialized.
schedules
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| name | String | Display name |
| description | String | Optional description |
| enabled | Boolean | Whether this schedule is active (can be overridden at runtime) |
| targetType | Enum | channel | group | sequence |
| nodeId | String | Target node (when targetType = channel) |
| ch | Integer | Target channel (when targetType = channel) |
| groupId | String | Target group (when targetType = group) |
| sequenceId | String | Target sequence (when targetType = sequence) |
| triggerMode | Enum | interval | specificTimes | daily |
| intervalMinutes | Integer | Firing interval (interval mode only, must be >= 1) |
| specificTimes[] | Array | Array of "HH:MM" strings in 24-hour format (specificTimes mode) |
| activeStart | String | Window start "HH:MM" (interval and daily modes) |
| activeEnd | String | Window end "HH:MM" (interval mode only) |
| activeDays | Array[7] | Boolean array, Monday-based: [0]=Mon, [1]=Tue, ... [6]=Sun |
Trigger mode behavior
- interval:Fires every intervalMinutes from activeStart, only while current time is within [activeStart, activeEnd] and activeDays[dayOfWeek] is true.
- specificTimes:Fires at each HH:MM in the specificTimes array, only on active days. The activeStart/activeEnd window is ignored.
- daily:Fires once at activeStart on each active day.
Validation rules
HelmOS validates the entire file with Zod on upload (POST /api/config). Key rules:
- Group channel references must point to existing (nodeId, ch) pairs.
- Sequence step targets must resolve to existing nodes/channels or groups.
- Schedule targets must resolve to existing nodes/channels, groups, or sequences.
- Duplicate node IDs are rejected.
- Interval schedules require intervalMinutes >= 1.
- Deduplication by YYYY-MM-DDTHH:MM key prevents double-firing on minute boundaries.