Protocol & Commands
One JSON message format for every command, response, and event — plus the full command reference.
Requests
Write a JSON object to CMD_IN. Every request has the same shape:
{
"method": "get" | "set", // read or write
"ns": "deviceState", // namespace (see below)
"prop": "PLAYER_SHIELD", // property within the namespace
"value": 100, // the new value (for "set"); omit for "get"
"id": "abc123" // your correlation id (echoed in the response)
}Give every request a unique id. Responses arrive on CMD_OUT carrying the same id, so you can match a reply to the request that produced it.
Responses
Responses are delivered as notifications on CMD_OUT:
// success
{ "status": "ok", "ns": "deviceState", "prop": "PLAYER_SHIELD", "value": 100, "id": "abc123" }
// error
{ "status": "error", "key": "invalidValue", "msg": "…", "data": "prop", "id": "abc123" }| Error key | Meaning |
|---|---|
unknownValue | The namespace or property is not recognised. |
invalidValue | The value was the wrong type or out of range for that property. |
missingValue | A required field (method / ns / prop) was missing. |
missingInput | The written value was empty. |
jsonParse… | The request was not valid JSON. |
Events
Events are unsolicited notifications on EVENTS_OUT. They use the same ns / prop / value fields but carry no status or ( usually) id — treat them as a fire-and-forget stream.
| ns | Shape | When |
|---|---|---|
deviceState | { "ns": "deviceState", "prop": "<KEY>", "value": <any> } | A state value changed. Fires only while DEVICE_APP_CONNECTED is true. High-frequency values are rate limited (GPS ~2s, battery ~5s). |
fsm | { "ns": "fsm", "prop": "state", "value": "<state>" } | The device entered a new game / UI state (e.g. IN_GAME → DEAD). |
kb | { "ns": "kb", "prop": "state", "value": { "isOpen": true, "msg": "…" } } | The device is requesting text input. Reply via the kb namespace. |
ota | { "ns": "ota", "prop": "progress", "value": { "phase", "status", "percent", "bytes", "total" } } | Firmware update progress during an OTA. |
Command reference
Commands are grouped by namespace (ns). Unless noted, the response value mirrors the request.
deviceState
Read, write, and subscribe to the device's live state. prop is any state key (see the Device State Reference). Any value that changes is also pushed as an event.
| Method | Property | Value | Description |
|---|---|---|---|
get | <KEY> | — | Read a value, e.g. PLAYER_SHIELD. GET GAME_TIME returns the live game clock rather than the stored field. |
set | <KEY> | new value | Write a value, e.g. set PLAYER_NAME to a string, or DEVICE_APP_CONNECTED to true. The value is coerced to the key's type; a type mismatch returns invalidValue. |
audio
Play and stop audio, and set the master volume.
| Method | Property | Value | Description |
|---|---|---|---|
set | startTrack | file path (string) | Play an audio file, e.g. "/audio/default/pickup.wav". |
set | masterVolume | 0–30 | Set the master volume. |
set | stopTrack | track number | Stop a playing track. |
get | isTrackPlaying | — | Returns whether audio is currently playing. |
rgb
Drive the addressable RGB LEDs directly.
| Method | Property | Value | Description |
|---|---|---|---|
set | setAll | [[r,g,b,brightness], …] | Set every pixel at once. One [r, g, b, brightness] array per pixel. |
set | setOne | [index,r,g,b,brightness] | Set a single pixel by index. |
fsm
The device's state machine — its current game / UI state. State transitions are also pushed as events.
| Method | Property | Value | Description |
|---|---|---|---|
get | state | — | Returns the current state name, e.g. HOME, IN_GAME, DEAD. |
set | state | state name | Force a state transition (advanced — most integrations only read this). |
wifi
WiFi used by the device for firmware updates.
| Method | Property | Value | Description |
|---|---|---|---|
set | credentials | { ssid, password } | Store the WiFi network the device should use for OTA updates. |
get | channel | — | Current radio channel. |
provisioning
Fleet grouping and firmware-update triggers.
| Method | Property | Value | Description |
|---|---|---|---|
set | group | group name (string) | Assign this device to a named update group. Group update triggers only affect devices in the same group. |
set | checkUpdate | — | Check this device for a firmware update AND broadcast the trigger to every device in the same group over the mesh. |
set | checkUpdateSelf | — | Check only this device for a firmware update (no mesh broadcast). |
kb
On-screen keyboard. When the device needs text it emits a kb event; reply with the text.
| Method | Property | Value | Description |
|---|---|---|---|
set | value | string | Supply the text the device requested via a kb event. |
Advanced
Lower-level namespaces used internally by the official app. Included for completeness.
| Method | Property | Value | Description |
|---|---|---|---|
get | screenController · currentScreenName | — | The name of the UI screen currently shown. |
set | esp-bridge · enabled | boolean | Relay ESP-NOW mesh traffic over the BLE event channel. |
set | irSender · 1 / 2 | — | Fire IR emitter 1 or 2. |
Worked example
Read the player's current ammo, then halve it:
// request -> CMD_IN
{ "method": "get", "ns": "deviceState", "prop": "WEAPON_AMMO", "id": "1" }
// response <- CMD_OUT
{ "status": "ok", "ns": "deviceState", "prop": "WEAPON_AMMO", "value": 48, "id": "1" }
// request -> CMD_IN
{ "method": "set", "ns": "deviceState", "prop": "WEAPON_AMMO", "value": 24, "id": "2" }
// response <- CMD_OUT
{ "status": "ok", "ns": "deviceState", "prop": "WEAPON_AMMO", "id": "2" }
// ...and because the value changed, an event arrives on EVENTS_OUT:
{ "ns": "deviceState", "prop": "WEAPON_AMMO", "value": 24 }