Skip to content

Serial JSON Protocol

greghulette edited this page Jul 28, 2026 · 4 revisions

Serial JSON Protocol

NaviCore exposes a newline‑delimited JSON protocol over its USB serial port (115200 baud, native USB‑CDC). The config tool uses it, but it's plain text — you can script against it from anything that opens the port. Each command is one line of JSON terminated by \n.

The same protocol is reachable over the WCB network via the Via WCB bridge (large payloads are fragmented). See WCB Network.


Command summary

Send Board replies Purpose
PING {"type":"PONG","version":"v0.2.0_…"} Liveness + firmware version. Also clears a stuck calibration mute.
GET_CONFIG {"type":"CONFIG","data":{…}} Full configuration as JSON.
{"type":"SET_CONFIG","data":{…}} {"type":"ACK","of":"SET_CONFIG","ok":true} Apply + persist config to /config.json on LittleFS. Baud / SBUS‑OUT / Maestro‑easing changes take effect live; see SET_CONFIG for failure variants.
{"type":"START_MONITOR"} ACK, then streams PWM_UPDATE Begin live telemetry (~every 50 ms).
{"type":"STOP_MONITOR"} {"type":"ACK","ok":true} Stop telemetry (also clears calibration mute).
{"type":"CALIB","on":true|false} {"type":"ACK","ok":true} Mute/unmute all action dispatch during calibration.
{"type":"RESET_DEFAULTS"} {"type":"ACK","ok":true} Reload factory defaults.
{"type":"REBOOT"} {"type":"ACK","ok":true,"msg":"rebooting"} ACKs, then restarts after 250 ms.
{"type":"TRIGGER","mode":1,"btn":3,"tap":1} {"type":"ACK","ok":true} Fire a virtual button press.
{"type":"WCB_SEND","target":2,"cmd":":PP100"} {"type":"ACK","ok":true} Send a WCB command (target:0 = broadcast, 1WCB_MAX_BOARDS = unicast).
{"type":"FORGET_PEER","id":3} (or "all":true) {"type":"ACK","of":"FORGET_PEER","ok":true,…} Drop a learned / auto‑joined ESP‑NOW peer from the peer table + NVS (one board, or all).
{"type":"SET_DEBUG_FLAGS","flags":N} {"type":"ACK","ok":true} Bitmask gating firmware [DISPATCH] logging.
{"type":"GET_WCB_STATUS"} {"type":"WCB_STATUS",…} Which WCB IDs are online.

Parse/format errors come back as {"type":"ERROR","msg":"…"} (with rxLen on JSON parse failures, so you can spot a truncated line).


SET_CONFIG

Applies a full config object to RAM, then persists it to /config.json on LittleFS. Every reply is tagged "of":"SET_CONFIG":

{"type":"ACK","of":"SET_CONFIG","ok":true}

Failure ACKs carry a msg:

ok / msg Cause
true Applied to RAM and saved to flash.
false · "parse failed" The line wasn't valid JSON.
false · "missing data" No top‑level data object.
false · "config apply failed" data was rejected while loading into RAM.
false · "applied to RAM but could not be saved to flash (LittleFS write error)" Config is live now but won't survive a reboot.

Most changes apply live — baud rates, the SBUS‑OUT toggle, and Maestro easing all re‑apply immediately, no reboot needed. The one exception is boardType: the pin profile is assigned only at boot, so changing the board also emits an extra line and needs a restart to take effect:

{"type":"INFO","msg":"boardType changed — reboot to apply the new pin profile"}

See Configuration Schema for the shape of data.


FORGET_PEER

Drops a learned (auto‑joined) ESP‑NOW peer from the runtime peer table and NVS. Forget one board by id, or all learned peers with "all":true:

{"type":"FORGET_PEER","id":3}
{"type":"FORGET_PEER","all":true}

Replies are tagged and echo what was forgotten:

{"type":"ACK","of":"FORGET_PEER","ok":true,"id":3}
{"type":"ACK","of":"FORGET_PEER","ok":true,"all":true}

An out‑of‑range id (with no all) or a not‑ready WCB radio returns {"ok":false} with a msg. The config tool re‑polls GET_WCB_STATUS afterward to refresh the panel. See WCB Network.


PWM_UPDATE (telemetry stream)

While the monitor is active the board emits, ~20×/second:

{
  "type":"PWM_UPDATE",
  "matrixCh":7, "modeCh":12,
  "matrixVal":1024, "modeVal":992,
  "btn":0, "mode":2,
  "sbus":{
    "ok":true, "fps":71, "frames":12345, "ageMs":3,
    "lost":false, "failsafe":false,
    "chCount":16, "frameLen":25,
    "channels":[ … per-channel SBUS values … ]
  }
}
  • matrixVal / modeVal — raw SBUS values on the matrix and mode channels.
  • btn — decoded matrix button (0 = none); mode — current mode (1‑3).
  • sbus.ok — true only when frames are flowing, no lost frame, and data is fresh (<500 ms).
  • sbus.chCount / frameLen — 16/25 = SBUS‑16, 24/36 = SBUS‑24.

TRIGGER

{"type":"TRIGGER","mode":1,"btn":3,"tap":1}
  • mode 1–3, btn 1–36, tap 1–3. Out‑of‑range values get a {"type":"ACK","ok":false,"msg":"bad mode/btn/tap"} reply. Fires the mapped actions exactly as a physical press would.
  • btn spans all 36 matrix‑channel slots: 121 are the physical matrix slots drawn on the TX graphic, 2236 are the 15 logical matrix‑channel bands (the Logical Buttons in the config tool). See Configuration Schema.

SET_DEBUG_FLAGS

A bitmask enabling per‑category [DISPATCH] log lines on the USB console (default 0 = silent):

Bit Category
1<<0 Maestro
1<<1 WCB (unicast + broadcast)
1<<2 WLED (;L<id> dispatch — local WcbWled::emit + remote forward)
1<<3 HCR
1<<4 MP3
1<<5 Serial

So {"flags":7} (1<<0 | 1<<1 | 1<<2) traces Maestro, WCB, and WLED dispatch.

GET_WCB_STATUS

Poll the WCB Status panel's data. The reply carries several parallel arrays, all indexed from board 1 up to the highest known board (which can exceed quantity when boards are auto‑discovered above the configured floor):

{
  "type":"WCB_STATUS", "quantity":4, "self":20,
  "online":[1,0,1,1],
  "known":[1,0,1,1],
  "clients":[0,0,0,0],
  "temporary":[0,0,0,0],
  "aliases":["","","dome","body"],
  "portLabels":[["","","","",""], ]
}
Field Meaning
quantity Configured board count (the floor).
self This board's WCB device ID; it always reports online = 1.
online[] 1 = board i+1 is live now (WCB heartbeat, or a fresh WDP advert for a client).
known[] 1 = render this slot — includes auto‑discovered boards above quantity.
clients[] 1 = a client device (mesh monitor / other controller), not a WCB board.
temporary[] 1 = a WDP "temporary" peer (e.g. a mgmt relay); never learned/persisted, so it drops off once its advert ages out.
aliases[] Friendly ?WHOAMI name per board; "" until the board answers (needs ?SPECIAL,ON to reply).
portLabels[] Per‑board 5‑element array of WDP serial‑port device labels (ports 1–5); "" = unlabeled. USB path only — the Via‑WCB bridge's frame can't carry these, so a bridged tool falls back to plain Serial <n>.

See WCB Network for how boards join the mesh and Remote Management over WCB for the Via‑WCB bridge.


Notes for scripting

  • One JSON object per line, \n‑terminated.
  • SET_CONFIG payloads can be several KB; the firmware sizes its RX buffer for this, but if you bridge over WCB the tool fragments them for you.
  • Send a PING first — it also clears any stale calibration mute left by a crashed page.

Clone this wiki locally