Commands vs. Statics — Quick Reference
Understanding command execution paths, static updates, timeouts, and field classification for Voodoo Cloud Display Devices.
Info
device(s) endpoint, with a focus on commands vs. statics, timeouts, and why certain fields are accepted, ignored, or reinterpreted.TL;DR
- Commands drive work → time-bound → use
seconds - Statics describe state → persistent → no timeout
seconds≠displaytimeout- Settings persist; commands do not
- When in doubt: commands are actions, statics are context
1. Two Execution Paths: Commands vs. Statics
Every API request is classified into exactly one of these paths:
- Command execution (dynamic, time-bound)
- Static update (persistent background state)
Which path is taken is determined by what fields are present, not by intent.
2. Commands (Dynamic, Time-Bound)
Commands represent active work that a human is expected to complete.
What Makes a Request a Command
A request is treated as a command if either of the following is true:
- A
commandfield is present, or - Any
line1–line5field is present (the system will implicitly convert this into a flash command)
Command Behavior
- Commands expire after
seconds - On button press → ACK → command is cleared
- On timeout → NACK → command is cleared
- After clearing, the device immediately falls back to its statics
Example Command
{
"command": "display",
"line1": "Pack Order 12345",
"line2": "Qty: 3",
"color": "blue",
"seconds": 3600
}Tip
"line2": "Qty: 3" renders the text Qty: 3 on the second line of the display. In many workflows, it is better to use the convenience field "quantity": 3 instead, because that renders the quantity in the large box at the top left of the device.Important Rules
seconds = 0means never timeout (LED stays on until batteries fail)- Long-running commands are allowed but consume battery continuously
- Commands are not persistent state and are never remembered after ACK/NACK
3. Statics (Persistent Background State)
Statics define what the device displays when no command is active.
What Makes a Request a Static Update
A request is treated as a static update when:
- No
commandis present, and - At least one of
statica–statice,locationoverride,brightness, or similar settings is present
If any static line is provided, all static lines are normalized internally to ensure consistent display behavior.
Static Behavior
- Statics never timeout
- They persist until explicitly changed
- They do not generate ACKs or NACKs
- They consume minimal battery (no LED usage)
Example Static Update
{
"locationoverride": "PutWall 1|Cubby 34",
"statica": "Order 34455",
"staticb": "Waiting for Pack",
"arrow": "up"
}4. seconds vs. displaytimeout (Not Related)
These parameters control completely different systems.
| Parameter | Applies To | Meaning |
|---|---|---|
| seconds | Commands | How long before a command expires and NACKs |
| displaytimeout | Statics | How long DeviceID/location is temporarily shown after a button press |
Key Clarification
displaytimeoutnever affects LEDsdisplaytimeoutcannot cause NACKs- It only controls how long identifying information overlays statics
5. Settings Are Not Commands
Some fields are settings, not actions:
- brightness
- locationoverride
- displaytimeout
- statica–statice
These are remembered by the device and reused automatically.
Warning
Why:
- Settings updates require additional radio exchanges
- Extra exchanges add latency to commands
- Mixed intent makes behavior harder to reason about
6. Automatic Normalization (What the Platform Helps With)
Behind the scenes, the platform:
- Converts colors, arrows, icons, quantities, barcodes, and QR codes into device-native representations
- Automatically assigns arrows when a location is known
- Enforces maximum line lengths
- Prevents invalid combinations (e.g., statics inside commands)
- Ensures commands and statics remain logically separate
This allows integrators to send human-readable JSON while devices receive optimized instructions.
7. Recommended Pattern for Long-Lived States
❌ Anti-Pattern
- Very large
secondsvalues (hours/days) seconds = 0to handle pauses in work
✅ Recommended Pattern
- Use commands to drive active work
- Allow commands to timeout naturally
- On NACK, replace with a static message (e.g., "Waiting for Pack")
- Clear or update statics when work resumes
This approach:
- Preserves battery life
- Avoids surprise NACKs
- Produces predictable device behavior
8. Advanced Pattern: CALL-Based Reissue
Some integrations intentionally:
- Let commands timeout
- Display a static message instructing a long button press
- Receive a CALL event
- Re-issue the command in response
This ensures explicit human intent and avoids silent retries.
Field Classification Table
A) Path Selectors (decide whether it's a Command or a Static update)
| Field(s) | Classification | What it does | Notes / gotchas |
|---|---|---|---|
| command | Command selector | Forces the request onto the command execution path | If present, statics are not allowed in the same request (they'll be ignored/removed). |
| line1–line5 | Implicit command selector | If any line is present and no command, the system treats it as a command (typically flash) | This is the common "why did this become a command?" surprise. |
B) Command Payload Fields (meaningful when it's a command)
| Field(s) | Classification | What it does | Notes / gotchas |
|---|---|---|---|
| seconds | Command lifetime | How long until the command expires and can NACK | 0 means "never expire" → LED stays on until batteries die. |
| color / Color | Command attribute | LED color (normalized) | Accepts variants; normalized internally. |
| sound | Command attribute | Sound behavior (normalized) | Friendly values like beep/none may be translated to device-native encodings. |
| nonce | Command correlation | Caller-provided correlation ID | Useful for matching ACK/NACK/CALL responses. |
| location | Command addressing helper | Location alias used to resolve device and optionally auto-add arrow | When used in a command, it's treated as addressing/augmentation, not a persistent setting. |
| deviceid / deviceID / DeviceID | Targeting | Chooses the device | Canonicalized internally. |
C) Static Payload Fields (persistent settings + background display)
| Field(s) | Classification | What it does | Notes / gotchas |
|---|---|---|---|
| statica–statice | Static display lines | Persistent "background" text shown when idle | If you set any static line, the platform normalizes the full set for consistent behavior. |
| locationoverride | Static setting | Persistent "area|location" style label shown when idle | Used for long-lived context; survives between commands. |
| brightness | Static setting | Persistent brightness setting | Do not include in command requests (it's a setting, not an action). |
| displaytimeout | Static UI setting | How long DeviceID/location is shown after button press while idle | Not related to seconds; cannot cause NACKs. |
D) "Convenience" Fields (interpreted differently depending on Command vs Static)
These are the sneaky ones: they're accepted in both worlds, and might or might not persist.
| Field(s) | Classification | If sent with command… | If sent without command… |
|---|---|---|---|
| quantity / Quantity | Convenience/decoration | Rendered as a command display element | Becomes a static decoration (stored and shown when idle) |
| barcode / Barcode | Convenience/decoration | Rendered as a command display element | Becomes a static decoration (stored and shown when idle) |
| qrcode / QRcode | Convenience/decoration | Rendered as a command display element | Becomes a static decoration (stored and shown when idle) |
| arrow / Arrow | Convenience/decoration | Rendered as a command display element | Becomes a static decoration (stored and shown when idle) |
| icon / Icon | Convenience/decoration | Rendered as a command display element | Becomes a static decoration (stored and shown when idle) |
Practical takeaway: these "convenience" fields behave like extra lines in a command, but like persistent statics in a static update.
E) Fields Intentionally Suppressed/Ignored in Commands
| Field(s) | Classification | Why it's suppressed |
|---|---|---|
| brightness | Setting | Settings and actions are kept separate for predictable behavior and performance. |
| locationoverride | Setting | Commands don't set persistent context. |
| statica–statice | Setting/display | Statics are not allowed inside commands. |
| displaytimeout (and similar) | Setting | Commands should not change static UI configuration. |
Rule of Thumb to Remember
- If you want an LED + timeout behavior → it's a command (
command+seconds). - If you want something to "stick" between work → it's statics (
statica…statice,locationoverride,brightness). - If you include
line1…line5, you're in command land whether you meant to be or not.
Put Wall / Pack Wall Worked Example
Below is a Put Wall / Pack Wall worked example mapped end-to-end, using commands for short-lived actions and statics for long-lived state.
A. One-time provisioning per cubby (both sides)
Do this once when installing / mapping devices.
{
"locationoverride": "PutWall 1 | Cubby 34",
"displaytimeout": 15,
"brightness": 100
}What it means: Device always knows its putwall/cubby identity when idle. When someone taps the button while idle, it will briefly show DeviceID/location for 15s, then revert.
B. Put Side workflow (fast action)
Goal: Light the Put Side device briefly while the sorter drops units.
{
"command": "flash",
"line1": "PUT: Order 1959690",
"line2": "Qty: 2",
"color": "blue",
"seconds": 60,
"nonce": "1959690"
}What happens on the device:
- LED turns on (blue) and shows the message.
- Worker drops items and taps the button.
On button press → ACK → command clears:
- Device immediately falls back to its statics (location / any static lines).
If nobody taps in 60 seconds → NACK → command clears:
- This is fine on Put Side because it's supposed to be immediate. Your app can log NACK as "put not acknowledged" and potentially re-queue.
Info
seconds short (30–120s) so NACKs are meaningful.C. Pack Side workflow (may sit for hours)
Goal: If items are sitting in cubby waiting for packing, the device should keep showing state without draining batteries or generating NACK noise.
{
"locationoverride": "PutWall 1 | Cubby 34",
"statica": "READY TO PACK",
"staticb": "Order 1959690",
"staticc": "Units: 2",
"arrow": "up"
}What happens:
- No LED necessarily.
- This message stays forever (until changed).
- No timeout. No ACK/NACK. Minimal battery impact.
D. Trigger the packer at the moment packing should happen
When packing actually begins (or when you want to actively draw attention), use a command on Pack Side.
{
"command": "display",
"line1": "PACK NOW",
"line2": "Order 1959690",
"line3": "Units: 2",
"color": "green",
"seconds": 900,
"nonce": "1959690-pack"
}Behavior:
- LED on (green) up to 15 minutes.
- If packer taps → ACK → command clears → device returns to the PACK HOLD statics (unless you clear them).
E. What to do on ACK (packing completed)
When you get ACK for the pack command, you typically want to change the idle state.
{
"statica": "",
"staticb": "",
"staticc": "",
"staticd": "",
"statice": ""
}{
"statica": "PACK COMPLETE",
"staticb": "Order 1959690",
"staticc": "Good to ship"
}F. What to do on NACK (packing didn't happen in time)
This is where Pack Side differs from Put Side. If the pack command times out (NACK), don't keep reissuing a long-running command. Instead:
{
"statica": "WAITING FOR PACK",
"staticb": "Order 1959690",
"staticc": "Units: 2"
}Now:
- No more NACK spam.
- No battery drain from a stuck LED.
- The device still conveys exactly what's sitting there.
G. Optional advanced pattern: CALL-based reissue (human intent)
If you want the packer to explicitly say "I'm here, re-light it":
{
"statica": "HOLD BUTTON 4s",
"staticb": "to re-light pack",
"staticc": "Order 1959690",
"unsolicitedNonce": "reissueID-122298393"
}When worker holds the button:
- Device sends CALL with the unsolicitedNonce you specify
- Your system responds by reissuing the pack command
This is elegant because it avoids blind retries.
Warning
You can do it, but it turns Pack Side into "leave the LED on for hours/days", which is usually unnecessary battery drain and makes timeout signals meaningless. Statics carry the long-lived state better.
