code wiki / (root) / nx_iot_provision_softap.nx

nx_iot_provision_softap.nx

buildroot/runtime/nx_iot_provision_softap.nx

20900 B490 linesdepth 2pulls 2 transitivereach 1 importersview sourcekind librarytopic iot
docsdependenciesstructsconstsfunctions

about

nx_iot_provision_softap.nx -- the auto-pair STATE MACHINE. Roadmap: NISHI_IOT_HUB_ROADMAP.md Epoch 3 (PAIR), the rung that turns the anchor (WHO) + the vendor drivers (HOW) + the classifier (PROBE) into the operator's actual outcome: lights that re-join the house on their own, with NO manual re-pair step. THE PROBLEM THIS CLOSES (operator-reported, 2026-05-16 + 2026-06-18): "they disconnect all the time and blink and then I MANUALLY have to re-pair and then they duplicate in the app." The anchor already killed the duplicate (re-adopt -> same logical id). This kills the MANUAL step: when a fixture drops to its open pairing SoftAP (e.g. TP-LINK_HS210_C209), the hub scans for it, joins it on the free Wi-Fi 6E radio, pushes the house creds over the vendor's own pairing path, waits for it to re-join the LAN, verifies it, and anchors it -- no human in the loop, no new app row. WHAT THIS ORGAN IS (and is NOT): This is the pure, deterministic LOGIC -- a sealed-enum state machine. It takes the RESULT of each radio/driver step as an event and returns the NEXT action the runner must perform. The radio calls themselves (scan / join SoftAP / socket-send creds / re-probe LAN) are the Windows-native live step, injected by the caller. Keeping the logic pure + buffer-only makes the whole auto-pair flow gate-provable today, off the LAN, on every nxc2 backend -- and lets the live runner be a thin shim that just performs actions and feeds back events. NEVER-BRICK BY CONSTRUCTION (CLAUDE.md #26 -- ABSOLUTE, brand-critical): Provisioning is the one IoT flow that writes persistent device state (the Wi-Fi credential). The guarantee here is MECHANICAL, not an asserted promise: 1. The action alphabet (PROV_ACT_*) contains NO firmware/OTA/flash action. The machine is structurally incapable of emitting one. 2. The most device-touching action it CAN emit, PUSH_CREDS, carries only a bounded Wi-Fi credential over the vendor's documented, reversible pairing API; a rejected push leaves the device safe in pairing mode (PROV_FAIL_PUSH, recoverable) -- never a half-write. 3. nx_iot_prov_action_writes_firmware is a FAIL-SAFE classifier: it returns 0 only for the explicit allow-list of safe actions and 1 (= writes firmware = brick risk) for anything else, so a future

dependencies 1 imports · 1 importers

nx_iot_classify.nx nx_iot_provision_softap.nx nx_iot_provision_softap_test.nx

imports: nx_iot_classify.nx

imported by: nx_iot_provision_softap_test.nx

structs

233struct IotProvSession

consts

106const PROV_ST_IDLE: i64 = 0
107const PROV_ST_SCANNING: i64 = 1 // waiting for a scan result
108const PROV_ST_JOINING: i64 = 2 // joining the device SoftAP
109const PROV_ST_PUSHING: i64 = 3 // pushing house creds to the device
110const PROV_ST_AWAIT_REJOIN: i64 = 4 // device rebooting onto the home LAN
111const PROV_ST_VERIFYING: i64 = 5 // confirming reachability on the LAN
112const PROV_ST_ANCHORING: i64 = 6 // anchoring the stable identity
113const PROV_ST_DONE: i64 = 7 // terminal: provisioned + anchored
114const PROV_ST_FAILED: i64 = 8 // terminal: gave up (see fail_reason)
115const PROV_ST_N: i64 = 9
131const PROV_ACT_NONE: i64 = 0
132const PROV_ACT_SCAN: i64 = 1 // scan for open pairing SoftAPs
133const PROV_ACT_JOIN_AP: i64 = 2 // join the selected device SoftAP
134const PROV_ACT_PUSH_CREDS: i64 = 3 // send house Wi-Fi creds (reversible)
135const PROV_ACT_REJOIN_HOME: i64 = 4 // rejoin home LAN + probe for device
136const PROV_ACT_VERIFY: i64 = 5 // confirm device reachable on LAN
137const PROV_ACT_ANCHOR: i64 = 6 // anchor stable identity (no dup)
138const PROV_ACT_REPORT_DONE: i64 = 7 // terminal success
139const PROV_ACT_REPORT_FAIL: i64 = 8 // terminal failure
140const PROV_ACT_N: i64 = 9
150const PROV_EV_NONE: i64 = 0
151const PROV_EV_START: i64 = 1 // begin provisioning a device
152const PROV_EV_AP_FOUND: i64 = 2 // scan found a pairing AP (ssid given)
153const PROV_EV_AP_NONE: i64 = 3 // scan found no pairing AP
154const PROV_EV_JOIN_OK: i64 = 4
155const PROV_EV_JOIN_FAIL: i64 = 5
156const PROV_EV_PUSH_OK: i64 = 6
157const PROV_EV_PUSH_FAIL: i64 = 7
158const PROV_EV_REJOIN_OK: i64 = 8 // device seen on the home LAN
159const PROV_EV_REJOIN_FAIL: i64 = 9 // device never came back (timeout)
160const PROV_EV_VERIFY_OK: i64 = 10
161const PROV_EV_VERIFY_FAIL: i64 = 11
162const PROV_EV_ANCHOR_OK: i64 = 12 // anchor adopt succeeded (logical_id in arg)
163const PROV_EV_ANCHOR_FAIL: i64 = 13 // anchor rejected (e.g. registry full)
164const PROV_EV_N: i64 = 14
174const PROV_FAIL_NONE: i64 = 0
175const PROV_FAIL_NO_AP: i64 = 1 // scan found nothing to pair
176const PROV_FAIL_UNKNOWN_VENDOR: i64 = 2 // pairing AP, but no driver for it
177const PROV_FAIL_JOIN: i64 = 3 // could not join the SoftAP (retries gone)
178const PROV_FAIL_PUSH: i64 = 4 // creds push rejected (device left safe)
179const PROV_FAIL_REJOIN_TIMEOUT: i64 = 5 // device never re-joined the LAN
180const PROV_FAIL_VERIFY: i64 = 6 // on LAN but not reachable
181const PROV_FAIL_ANCHOR: i64 = 7 // anchor adopt failed
182const PROV_FAIL_BAD_ARG: i64 = 8 // null session at init
183const PROV_FAIL_N: i64 = 9
196const NX_IOT_PROV_MAX_ATTEMPTS: i64 = 3

functions

117func nx_iot_prov_state_is_valid(v: i64) -> i64
called by 1: main
142func nx_iot_prov_action_is_valid(v: i64) -> i64
166func nx_iot_prov_event_is_valid(v: i64) -> i64
185func nx_iot_prov_fail_is_valid(v: i64) -> i64
called by 1: main
206func nx_iot_prov_action_writes_firmware(act: i64) -> i64
222func nx_iot_prov_action_is_brick_safe(act: i64) -> i64
249func nx_iot_prov_init(s: *IotProvSession, max_attempts: i64) -> i64
called by 1: main
270func nx_iot_prov_is_pairing_ssid(ssid: *u8, n: i64) -> i64
called by 1: main calls 1: nx_iot_classify_by_ssid
287func nx_iot_prov_step(s: *IotProvSession, ev: i64,
444func nx_iot_prov_state(s: *IotProvSession) -> i64
called by 1: main
449func nx_iot_prov_action(s: *IotProvSession) -> i64
called by 1: main
454func nx_iot_prov_vendor(s: *IotProvSession) -> i64
called by 1: main
459func nx_iot_prov_fail_reason(s: *IotProvSession) -> i64
called by 1: main
464func nx_iot_prov_logical_id(s: *IotProvSession) -> i64
called by 1: main
469func nx_iot_prov_attempts(s: *IotProvSession) -> i64
called by 1: main
474func nx_iot_prov_ev_count(s: *IotProvSession) -> i64
called by 1: main
479func nx_iot_prov_is_terminal(s: *IotProvSession) -> i64
called by 1: main
486func nx_iot_prov_is_success(s: *IotProvSession) -> i64
called by 1: main