Update partition layout to 4MB factory/ota_0/ota_1 partitions for larger
firmware images. Add a 60-second validation timer that starts after the
hello message is sent on boot from an OTA partition. The partition is only
marked valid (via esp_ota_mark_app_valid_cancel_rollback) after receiving
a role message from the mothership. If the timer expires without role
receipt, the partition stays unconfirmed and the bootloader rolls back to
the previous firmware on next reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automatically detect the home router as a passive radar TX source,
eliminating need for a dedicated active TX node.
Firmware changes:
- During hello message, include ap_bssid and ap_channel from esp_wifi_sta_get_ap_info()
Mothership changes:
- On hello: extract ap_bssid; if >=80% of nodes report same BSSID create virtual node entry with virtual=1
- OUI lookup: embedded IEEE OUI registry as Go map compiled via go:embed; display router brand
- Detect AP BSSID change (router reboot/replacement) and emit system alert
- SQLite nodes table: add virtual BOOL, node_type TEXT, ap_bssid TEXT, ap_channel INT columns
Dashboard changes:
- Show "I detected your router (ASUS). Place it on the floor plan..." notification
- Render virtual AP nodes with distinct router icon in 3D view
- Drag-to-place virtual node (distinct router icon) in 3D editor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add git-based version header generation for firmware builds
- Implement SHA-256 hash verification for OTA downloads with mbedtls
- Add URL decoding for captive portal form parsing (spaces, special chars)
- Add mbedtls dependency for SHA-256 verification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- firmware: wire on-device motion hints to websocket_send_motion_hint()
with 1s rate-limit; csi_set_rate() now writes to g_state.packet_rate
- firmware: websocket_send_motion_hint() sends variance + MAC + timestamp
to mothership so rate controller ramps ahead of server-side detection
- mothership: RateController.OnMotionHint() preemptively ramps adjacent
nodes via SetAdjacentNodesFn callback (topology-aware burst propagation)
- mothership: idle timeout extended to 30s; variance_threshold=0 in active
mode (server handles detection), DefaultVarianceThreshold=1.0 in idle
- mothership: SendRoleToMAC() exposes dynamic role changes post-connect
- mothership: SendOTAToMAC() enables pushing firmware updates to nodes
- mothership: OTA status events are now logged with state and progress %
Protocol is backward-compatible: binary CSI frames work as in Phase 1;
JSON control messages are additive on the same single WebSocket per node.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dashboard hub broadcasts motion state changes immediately on transition
(idle↔motion) via BroadcastMotionState; periodic state snapshots include
motion_states for new client init
- Per-link presence badge (green CLEAR / red MOTION) rendered in link list
alongside global presence indicator in status bar
- Amplitude mean time-series chart (60 s rolling window) for selected link,
line segments colored by motion state at each sample
- Fix: links created from JSON link_active/state events now initialize
ampHistory and lastAmpSample so time-series accumulates from first frame
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>