Expand description
Compact node status and identity for the auxiliary radio lane.
An operator paired only to a ground station sees the drone it relays as a
bare row: no capabilities, no services, no board. Everything the fleet view
wants lives on the drone’s own /api/status, and the WFB link carries no IP,
so none of it reaches the ground node. This module is the wire shape that
closes that gap, carried on the auxiliary lane’s status and identity
channels.
§Why a dedicated schema and not the heartbeat payload
The cloud heartbeat already assembles exactly these facts, but its payload is
a hundred-plus camelCase fields sized for an HTTP POST. One aux frame carries
AUX_MAX_PAYLOAD = 1200 bytes, and the
lane is shared with MAVLink at telemetry rates. So this is a deliberately
separate, deliberately small projection: the fields a ground operator acts
on, and nothing else.
Two economies do the work. The encoding is msgpack rather than JSON, matching the state socket’s v2 form. Field names are two or three characters, because msgpack writes map keys as strings and twenty-odd long names would spend several hundred bytes on nothing but labels. Every field is documented here, which is where the readability lives.
§Absent means unknown, never zero
Every optional field is skip_serializing_if, so a fact the drone could not
read is ABSENT from the frame rather than sent as a plausible-looking 0 or
false. A ground reader shows “unknown”, never a fabricated reading.
This is also what keeps the frame small in practice: a
node with no flight controller spends no bytes saying so.
§Trimming, not fragmentation
A snapshot that will not fit is TRIMMED, in a fixed order, until it does. It is never split across frames.
Fragmentation was considered and rejected. It would need a reassembly buffer, a reassembly timeout, and a partial-frame policy on the receiving side, and on a lossy radio lane one dropped fragment discards the whole snapshot anyway. Status is periodic and idempotent: losing one costs a second, and the next is complete. Trimming keeps the receiver a pure function of one datagram with no cross-frame state to get wrong.
In practice trimming never fires. A fully-populated snapshot measures a few hundred bytes against a 1200-byte budget, and a test pins the worst case with every field at its maximum length. The ladder exists so that a future field, or an unusually long board name, degrades predictably instead of silently failing to send.
§Bounded by construction
Every variable-length field is capped at build time by the NodeStatus
builders and NodeIdentity::build — strings truncated, the failed-service list
capped at MAX_FAILED_NAMES. The cap is not a formality: the failed-unit
list is the one field an operator most wants and the one that grows without
bound on a badly broken node, which is exactly when the lane must not be
flooded.
Structs§
- Node
Identity - A drone’s identity, sent less often than status because it does not change.
- Node
Status - A compact projection of a node’s status, sized for one aux frame.
Constants§
- MAX_
DEVICE_ ID - Longest device id carried. Real ids are 12 hex characters, so this is headroom rather than a limit that bites.
- MAX_
FAILED_ NAMES - Most failed-unit names carried in one snapshot.
- MAX_
NAME - Longest human-facing node name carried.
- MAX_
PLUGIN_ LIST - Longest plugin-inventory string carried:
pluginId@contractVersionentries joined by commas. Capped so a node with many plugins degrades predictably instead of overflowing the frame; a real node runs a handful. - MAX_
SHORT - Longest short free-text field (agent version, board name, SoC, firmware family, camera and video state).
- MAX_
UNIT_ NAME - Longest single failed-unit name carried.
- NODE_
STATUS_ VERSION - Schema version for both the status and identity frames.
Functions§
- parse_
plugin_ list - Parse a plugin-inventory string produced by
plugin_list_stringback into(id, contractVersion)pairs. A malformed entry is skipped rather than failing the whole parse, so one bad token never blinds a version check. - plugin_
list_ string - Format an installed-plugin inventory as
id@verentries joined by commas, sorted by id so the string is stable regardless of install order.Nonewhen the inventory is empty. Plugin ids are reverse-DNS and carry no@, so the last@always separates id from version on decode.