- /ws/node endpoint: one goroutine per connection, bidirectional - Binary frames: 24-byte header → CSIFrame struct; payload as []int8 I/Q pairs - JSON frames: dispatched by "type" field (hello, health, ble, motion_hint, ota_status) - Per-link ring buffer: 256-sample circular, keyed by (node_mac, peer_mac) - Node identity from first "hello" — no pre-registration required - Used gorilla/websocket: mature, SetReadDeadline, binary frame support - mDNS via hashicorp/mdns at _spaxel._tcp.local:8080 - Ping/pong keepalive: 30s ping interval, 60s read deadline - Malformed frame tracking: warn at 100/min, close at 1000/min Complete: frame parsing, ring buffers, mDNS, hello/health/ble dispatch, tests (22 passing) Remaining: OTA command dispatch, /ws/dashboard publisher, SQLite fleet manager (Phase 2) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Spaxel Implementation Progress
Phase 1 — Foundation
Goal: Bare-minimum loop from ESP32 to browser. Zero-config with passive radar and mDNS from day one.
Status
| Item | Status | Notes |
|---|---|---|
| ESP32 firmware skeleton | Not started | |
| Passive radar support | Not started | (part of firmware) |
| BLE scanning | Not started | (part of firmware) |
| Mothership WebSocket ingestion | Done | See iteration 1 below |
| Dashboard skeleton | Not started | |
| Docker packaging | Not started |
Iteration Log
Iteration 1 — 2026-03-26
Completed: Mothership WebSocket ingestion server
Implemented the core ingestion server in Go with:
- Module structure:
mothership/withcmd/mothership/entrypoint andinternal/ingestion/package - WebSocket endpoint:
/ws/nodeaccepts bidirectional connections from ESP32 nodes - Binary frame parsing: 24-byte header + variable payload, per spec in plan.md
- Validation: min/max length, payload size match, channel validity (1-14), subcarrier limit (128)
- Malformed frame tracking with warn/close thresholds (100/1000 per minute)
- JSON message handling: Parses hello, health, ble, motion_hint, ota_status
- Per-link ring buffers: 256-sample circular buffers keyed by
nodeMAC:peerMAC - Connection lifecycle: Node registration via hello, ping/pong keepalive (30s/60s), graceful shutdown
- mDNS advertisement:
_spaxel._tcp.localvia github.com/hashicorp/mdns - Role/config push: Sends initial
rxrole and 20 Hz config on connect - Health endpoint:
GET /healthzreturns{"status":"ok","version":"..."}
Dependencies used:
github.com/go-chi/chi— HTTP routinggithub.com/gorilla/websocket— WebSocket servergithub.com/hashicorp/mdns— mDNS advertisement
Tests: 22 tests covering frame parsing, JSON messages, and ring buffer operations. All pass.
Files created:
mothership/
├── cmd/mothership/main.go
├── go.mod
├── go.sum
└── internal/ingestion/
├── frame.go
├── frame_test.go
├── message.go
├── message_test.go
├── ring.go
├── ring_test.go
└── server.go
Remaining for Phase 1:
- ESP32 firmware (WiFi, mDNS discovery, CSI capture, WebSocket client)
- Dashboard skeleton (HTML/JS + Three.js)
- Docker packaging