Status matrix
A single-glance comparison of the spec/ contract against what is
built, functioning, and bench-tested in firmware, plus the
roadmap ahead.
This is a derived view, hand-maintained. The source of truth is
spec/frames.yaml, the firmware infirmware/, and the dated entries in status.md. When code lands, update this file (or regenerate it) — runtools/spec-check.shto catch spec-version drift. Structured as stable tables so a future web status page can parse it.
- As of: 2026-06-29
- Spec version:
frames.yamlv0.5.0 - Current phase: Phase 2 — single-cluster MVP (firmware bring-up)
- Working link: Zephyr field node (T114 + XIAO nRF52840) ⇄ ESP-IDF hub (Heltec V3.1), endpoint↔hub direct (no router tier yet).
Legend: ✅ done · 🟡 partial · ⬜ not started · — n/a
Protocol message types (spec 0.5.0)
Section titled “Protocol message types (spec 0.5.0)”| Code | Message | Spec payload | Field FW | Hub FW | Bench-tested | Phase |
|---|---|---|---|---|---|---|
| 0x01 | STATUS | ✅ ratified | ✅ encode | ✅ decode | ✅ | 2 |
| 0x02 | STATUS_ACK | ✅ ratified | ✅ decode | ✅ encode | ✅ | 2 |
| 0x03 | JOIN | ✅ ratified | ✅ encode | ✅ decode | ✅ | 2 |
| 0x04 | JOIN_ACK | ✅ ratified | ✅ decode | ✅ encode | ✅ | 2 |
| 0x05 | ANNOUNCE | ✅ ratified | ✅ encode | ✅ decode | ✅ | 2 |
| 0x06 | WHO_ARE_YOU | ⬜ no payload | ⬜ | ⬜ | ⬜ | 2/4 |
| 0x07 | COMMAND | ✅ ratified | ✅ decode | ✅ encode | 🟡 1/12 cmds | 2 |
| 0x08 | COMMAND_ACK | ✅ ratified | ✅ encode | ✅ decode | ✅ | 2 |
| 0x10 | ROUTING_BEACON | ⬜ pending | ⬜ | ⬜ | ⬜ | 3 |
| 0x11 | ROUTER_UPLINK | ⬜ type only | ⬜ | ⬜ | ⬜ | 3 |
| 0x12 | ROUTER_DOWNLINK | ⬜ type only | ⬜ | ⬜ | ⬜ | 3 |
| 0x20 | KEY_ROLLOVER | ⬜ type only | ⬜ | ⬜ | ⬜ | 5 |
| 0x21 | HELP | ⬜ no payload | 🟡 help-mode flag in STATUS, not a HELP frame | — | 🟡 | 3 |
The full single-link message layer (0x01–0x08, minus the optional 0x06 WHO_ARE_YOU) is built and hardware-verified on two field boards + hub. Everything ⬜ is router-tier (Phase 3) or later.
COMMAND sub-commands (apply handlers)
Section titled “COMMAND sub-commands (apply handlers)”The COMMAND frame is complete (decode + inner CMAC verify + replay-check
- COMMAND_ACK). Only one command has an apply handler; the rest decode
and verify, then return
unknown_cmd_type.
| Cmd | Name | Privilege | Apply handler | Needed for |
|---|---|---|---|---|
| 0x06 | set_ack_interval | field | ✅ | (working, persisted) |
| 0x05 | set_check_in_interval | field | ⬜ | Phase 2 sensing |
| 0x07 | wake_ble | field | ⬜ | Phase 4 |
| 0x01 | set_router_list | admin | ⬜ | Phase 3 |
| 0x02 | add_router_to_list | admin | ⬜ | Phase 3 |
| 0x03 | remove_router_from_list | admin | ⬜ | Phase 3 |
| 0x04 | reorder_router_list | admin | ⬜ | Phase 3 |
| 0x08 | rotate_key | admin | ⬜ | Phase 5 |
| 0x09 | request_announce | none | ⬜ | Phase 2/4 |
| 0x0A | factory_reset_remote | admin | ⬜ | Phase 4 |
| 0x0B | set_low_batt_threshold | admin | ⬜ | Phase 2 |
| 0x0C | set_autonomous_reorder | admin | ⬜ | Phase 3 |
Capabilities (beyond frames)
Section titled “Capabilities (beyond frames)”| Capability | Status | Notes |
|---|---|---|
| AES-128-CCM envelope (K_group) | ✅ | both MCU families, cross-library (PSA + mbedTLS) |
| Inner COMMAND auth (AES-CMAC / K_field) | ✅ | |
| Replay protection (frame + command layers) | ✅ | mod-2¹⁶ seq window + cmd_seq |
| NVS persistence (seq / cmd_seq / config) | ✅ | reboot-safe, both sides |
| ACK/retry → help-mode state machine | ✅ | |
| JOIN discovery handshake on boot | ✅ | endpoint↔hub direct |
| Build-time per-board node IDs | ✅ | stand-in for the Phase-4 wizard |
| Board-onboarding harness + tooling | ✅ | /spec-check, /build-all, spec-guard hook |
| Endpoint deep sleep | ⬜ | timed 5 s loop today; Phase 2 |
| Reed-switch trigger | ⬜ | Phase 2 — the “trap tripped” half |
| Hub SQLite history | ⬜ | Phase 2 |
| Hub web UI | ⬜ | Phase 2 — the “alert in UI” half |
| MQTT relay (hub) | ⬜ | Phase 2, default off |
| Router tier (DV routing) | ⬜ | Phase 3 |
| BLE provisioning + deployment wizard | ⬜ | Phase 4 |
| Real RTC / wall-clock source | ⬜ | time_valid stubbed for now |
| Key rotation (KEY_ROLLOVER) | ⬜ | Phase 5 |
| Deep-sleep current baseline | ⬜ | blocked on a PPK2 / power analyser |
Hardware (dev boards)
Section titled “Hardware (dev boards)”| Board | Role | Firmware verified | Node ID |
|---|---|---|---|
| Heltec T114 v1 | trap (endpoint only, ADR-16) | ✅ JOIN handshake | 0x1 |
| Heltec T114 v2 | trap / router | ✅ (same build as v1) | 0x1 |
| Seeed XIAO nRF52840 | trap / router | ✅ JOIN handshake | 0x2 |
| Heltec WiFi LoRa 32 V3.1 | hub | ✅ hub firmware | 0xA0 |
| Seeed XIAO ESP32-S3 | hub | 🟡 Arduino-validated only; hub FW targets V3.1 pins | — |
| SenseCAP Indicator | hub (Phase 2 target) | ⬜ | — |
Roadmap
Section titled “Roadmap”| Phase | Band | Theme | Status | Exit criterion |
|---|---|---|---|---|
| 0 | MVP | Specification | ✅ done | docs reviewed & agreed |
| 1 | MVP | Bring-up (hello-LoRa) | ✅ done¹ | T114 → RX plaintext, repeatable |
| 2 | MVP | Single-cluster MVN | 🟡 in progress | reed-switch trip → hub web-UI alert in 30 s |
| 3 | MVP | Multi-cluster / router tier | ⬜ | 2-hop endpoint→R→R→hub + failover |
| 4 | MVP | Provisioning & ops | ⬜ | deploy a node with only the wizard |
| 5 | MVP | Crypto hardening | ⬜ | rotate K_group cluster-wide, no lost check-in |
| 6 | MVP | Field pilot + Trap.NZ | ⬜ | 2 wks live, ≥95% check-ins, Trap.NZ ≤5 min |
| 7 | v1.0 | Headless / outdoor hub | ⬜ | hub with no station, outbound only |
| 8 | v1.0 | Cellular hub | ⬜ | off-grid + remote reporting |
| 8b | v1.0 | Central service | ⬜ | containerised, single-org |
| 9 | v1.5 | Multi-tenant + web flasher | ⬜ | public buyer self-onboards in 10 min |
| 10 | v2.0+ | Hardening / OIDC / OTA | ⬜ | enterprise features |
| 11 | OSS | Release & adoption | ⬜ | open repo, BOM, manual |
¹ Phase 1’s wire-link is met; the deep-sleep current baseline is the one outstanding item, gated on test equipment (PPK2).
Phase 2 — what’s left
Section titled “Phase 2 — what’s left”The protocol axis is done (the ✅ block above). What remains is the application / sensing axis the exit criterion measures, in two tracks:
- Trap side: reed-switch trigger + endpoint deep sleep, plus the
set_check_in_interval(0x05) andset_low_batt_threshold(0x0B) apply handlers. - Hub side: SQLite history → minimal web UI (nodes + last-seen) → optional MQTT relay.
The exit demo (“trip the reed switch, alert in the hub web UI within 30 s”) needs at least one deliverable from each track. Neither has started. See roadmap.md Phase 2 for the full list.