Implemented Component 17 of the Spaxel plan - a pre-deployment simulator
that allows users to define virtual spaces, place virtual nodes, and
simulate walkers to predict detection quality before purchasing hardware.
Key features:
- Virtual space definition with rooms and wall segments
- Virtual node placement with corner positioning suggestions
- Synthetic walkers (random walk and path-following modes)
- GDOP (Geometric Dilution of Precision) computation for coverage quality
- Two-ray RF propagation model (direct + first-order reflection)
- Wall penetration loss by material type (drywall, brick, concrete, glass, metal)
- Fresnel zone computation and zone decay
- Shopping list generation with hardware recommendations
- REST API endpoints for simulation control and results
Files added:
- internal/simulator/space.go - Virtual space and room definitions
- internal/simulator/node.go - Virtual node management
- internal/simulator/walker.go - Synthetic walker simulation
- internal/simulator/gdop.go - GDOP computation and coverage analysis
- internal/simulator/propagation.go - RF propagation model
- internal/simulator/engine.go - Simulation engine (bug fixes)
- internal/simulator/handler.go - HTTP API handlers
- internal/api/simulator.go - REST API endpoints
- internal/simulator/simulator_test.go - Comprehensive tests
- internal/simulator/space_test.go - Space definition tests
Integration:
- Simulator API registered in main mothership server at /api/simulator/*
- Endpoints for space, nodes, walkers, GDOP computation, and simulation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add X-ray overlay showing contributing links to detections with confidence breakdown.
- Users can click "Why?" on any blob to see detailed explanation
- Contributing links are highlighted with Fresnel zone visualization
- Per-link contribution breakdown shows deltaRMS, zone number, weight
- BLE identity match details displayed when available
- Confidence gauge shows overall detection certainty
Explainability is accessible via:
- Right-click context menu on blob figures
- "Why?" button in blob hover tooltip
- Click directly on humanoid blob figures
- Timeline event "Why?" buttons
Accepts: Users can see exactly why a detection was triggered with visual overlays and confidence metrics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 8 implementation: Activity Timeline (Component 27)
- Tap-to-jump navigation: Click any event to create replay session and seek to that moment
- Inline feedback display: Thumbs up/down buttons on each event for detection feedback
- Replay API integration: Creates replay window around event timestamp (±5 seconds)
- Feedback API: New /api/feedback endpoint for correct/incorrect/missed detection reports
- Event loading improvements: Real-time WebSocket event insertion with animation
- Filter UI: Type, zone, person, time range, and search filters
- Load more pagination: Keyset cursor-based pagination for large event sets
Acceptance criteria met:
- Users can view all system events chronologically
- Tap any event to jump to that moment in time via replay mode
- Inline feedback buttons allow marking detections correct/incorrect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement time-travel debugging, CSI simulator, and pre-deployment
simulator for deep system analysis and tuning.
Time-Travel Debugging:
- Replay session management with seek/play/pause controls
- Parameter tuning overlay with instant preview
- CSI replay store with circular buffer for 48h retention
- REST API for replay control (/api/replay/*)
CSI Simulator CLI (cmd/sim/main.go):
- Virtual ESP32-S3 nodes with synthetic CSI generation
- Walker simulation with random walk or path-following
- Fresnel zone modulation based on walker positions
- BLE advertisement simulation for identity testing
- WebSocket integration with mothership
Pre-Deployment Simulator:
- Virtual space definition with 3D node placement
- Synthetic walker generation and movement simulation
- Fresnel zone accumulation for blob detection
- GDOP map computation for coverage quality visualization
- Deployment recommendations based on coverage analysis
- SSE endpoint for real-time simulation updates
Dashboard Integration:
- Fresnel zone ellipsoid rendering (already in viz3d.js)
- Activity timeline with tap-to-jump (already in timeline.js)
- Detection explainability with X-ray overlay (already in explainability.js)
Exit Criteria Met:
- Time-travel replays historical CSI data with seek/play/pause
- Simulator produces realistic synthetic CSI and blob detections
- Fresnel zone overlay renders wireframe ellipsoids between links
- Developers can tune parameters and see instant results
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement localization that learns from ground truth data.
- BLE integration as ground truth source: BLE RSSI trilateration provides
continuous position estimates for registered devices
- Fresnel zone weight refinement: SGD-based per-link weight learning
- Continuous weight adjustment based on BLE-blob position feedback
- SelfImprovingLocalizer ties together BLE ground truth, weight learning,
and fusion engine
- REST API endpoints for weights, ground truth, accuracy tracking
Acceptance: Localization accuracy improves automatically as BLE ground
truth data accumulates.
Document the complete presence prediction system implementation
for Home Assistant integration with:
- Per-person transition probability tracking with Laplace smoothing
- Per-zone occupancy patterns from historical data
- Time-slot based predictions via Monte Carlo simulation
- HA sensor exposure with auto-discovery (3 sensors per person)
- Accuracy tracking targeting >75% at 15-minute horizon
All acceptance criteria for presence prediction have been met.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement REST API endpoints for managing learned weights and tracking
improvement in the self-improving localization system.
- Add LocalizationHandler with endpoints for:
- GET /api/localization/weights - get all learned link weights
- GET /api/localization/weights/{linkID} - get specific link weight
- POST /api/localization/weights/reset - reset all weights to default
- GET /api/localization/spatial-weights - get spatial weights per zone
- GET /api/localization/groundtruth/* - ground truth sample management
- GET /api/localization/accuracy/* - position accuracy tracking
- GET /api/localization/learning/* - learning progress and history
- Integrate spatial weight learner into fusion engine:
- Add AddLinkInfluenceWithSpatialWeights to grid.go for per-cell weight application
- Update Fuse() in fusion.go to use spatial weight functions when available
- Apply both sigma adjustments and spatial weights for Fresnel zone computation
- Add comprehensive table-driven tests for all API endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implemented prediction API handler with comprehensive REST endpoints:
- GET /api/predictions - Get all predictions (optional filter by person/horizon)
- GET /api/predictions/stats - Get prediction statistics and data age
- POST /api/predictions/recompute - Force probability recomputation
- GET /api/predictions/accuracy - Get accuracy stats for all people
- GET /api/predictions/accuracy/overall - Get overall system accuracy
- GET /api/predictions/accuracy/{personID} - Get person-specific accuracy
- GET /api/predictions/pending - Get pending prediction count
- GET /api/predictions/patterns/zones - Get zone occupancy patterns
- GET /api/predictions/patterns/zones/{zoneID} - Get pattern for specific zone
- POST /api/predictions/patterns/compute - Compute zone occupancy patterns
- GET /api/predictions/horizon - Get Monte Carlo horizon predictions
- GET /api/predictions/horizon/{personID} - Get horizon prediction for person
The implementation includes:
- Proper error handling with appropriate HTTP status codes
- Query parameter support for filtering (person, horizon)
- JSON responses for all endpoints
- Helper function for logging prediction accuracy
- Table-driven tests for all endpoints
HA sensor exposure for predictions was already implemented in the MQTT
client via PublishPredictionSensors() and UpdatePredictionState() methods.
Accepts the 75% accuracy target at 15-minute horizon per specification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements comprehensive anomaly detection system that learns normal household
patterns over 7+ days and alerts on deviations. Transforms spaxel into a basic
home security system.
Core features:
- Normal behaviour model: statistical tracking of occupancy patterns per
(hour_of_week, zone_id) slot with expected occupancy, typical person count,
and typical BLE devices
- Four anomaly types: unusual hour presence, unknown BLE device, motion during
away mode, unusual dwell duration
- Security mode: lowered thresholds, immediate alerts, bypasses quiet hours
- Auto-away/disarm: automatic security mode activation based on BLE device
presence (15min absence, auto-disarm on device return)
- Alert chain: staged notifications (dashboard → push → webhook → escalation)
- WebSocket integration: real-time anomaly broadcasts to dashboard
API endpoints:
- GET/POST /api/mode: system mode control (home/away/sleep)
- GET /api/security/status: current security state
Tests cover all anomaly types, alert chain timing, security mode thresholds,
auto-away/disarm, acknowledgement flow, and cooldown deduplication.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verified the diurnal adaptive baseline system is fully implemented:
- 24 hourly slots per link per subcarrier
- 7-day learning phase with >=300 samples/slot requirement
- Motion-gated updates with outlier protection
- 15-minute crossfade at hour boundaries
- SQLite persistence with diurnal_baselines table
- 24-hour polar chart dashboard visualization
- REST API endpoints for diurnal data
- Comprehensive test coverage (45+ tests)
All acceptance criteria met:
- Baseline correctly crossfades at hour boundaries (±60s)
- Motion events during learning do not corrupt slots
- Polar chart renders for links with >=1 ready slot
- No performance regression: baseline lookup remains O(1)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add REST API for diurnal baseline data:
- GET /api/diurnal/status - learning status for all links
- GET /api/diurnal/slots/{linkID} - slot data for specific link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Floor plan upload panel with image selection and preview
- Two-point calibration UI with pixel distance measurement
- Real-world distance input for scale computation
- Pixel-to-meter scale factor calculation and storage
- Fixed floor plan image serving at /floorplan/image.png
- Integration with Viz3D ground plane texture
- CSS styling for floor plan setup panel
- Image persists across server restart via SQLite
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update .beads/issues.jsonl and .needle-predispatch-sha after
remote rebase to maintain tracking state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: Add POST /api/auth/change-pin endpoint
- Requires valid session; body: {old_pin, new_pin}
- Verifies old PIN against bcrypt hash; returns 403 on mismatch
- Hashes new PIN with bcrypt cost=12
- Existing sessions remain valid after PIN change
- Returns {ok:true} on success
- Dashboard: Security section in settings panel
- Add "Security" section with Change PIN button
- Modal form: old PIN → new PIN → confirm new PIN → Submit
- Inline error display for incorrect current PIN (403)
- Success toast notification on PIN change
- Validation: 4-8 digits, numeric only, PINs must match, new ≠ old
- Tests: Add comprehensive tests for change PIN endpoint
- Success case: old PIN verified, new PIN works
- Wrong old PIN: returns 403, original PIN still works
- Unauthenticated: returns 401
- Invalid new PIN: validation for length, digits, etc.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All components complete:
- Firmware: LED blink at 5Hz via FreeRTOS task, configurable GPIO
- Mothership: POST /api/nodes/{mac}/identify endpoint, WebSocket sending
- Dashboard: Identify button in fleet panel and 3D view context menu
Acceptance criteria met:
✓ LED blinks at ~5 Hz for specified duration
✓ Blink stops automatically when duration_ms expires
✓ REST endpoint returns 404 for disconnected nodes
✓ LED GPIO configurable via sdkconfig (default GPIO8)
✓ Dashboard integration complete
- Fleet status page now has 'Identify' button per row that POSTs to /api/nodes/{mac}/identify
- 3D view right-click context menu has 'Identify (blink LED)' option for nodes
- Both options trigger LED blink on the selected node for identification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'Identify' button to fleet health panel role list for online nodes
- Add CSS styling for fleet identify button
- Add identifyNode function to FleetPanel public API
- 3D view context menu with 'Identify (blink LED)' already implemented
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 'Identify (blink LED)' option to the right-click context menu
in the 3D view that POSTs to /api/nodes/{mac}/identify.
The context menu appears when right-clicking on a node mesh in the
3D visualization. Uses recursive raycasting to properly detect
both standard node meshes and router node groups.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added tests for:
- Auto-away activation when all registered BLE devices absent for 15+ minutes
- Auto-disarm triggering when registered BLE device returns with strong RSSI
- Manual override pausing auto-away detection
- System mode GET/PUT REST API endpoints
- Edge cases: no registered devices, weak BLE signals, unregistered devices
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a lightning bolt (⚡) Identify button per node row in the
fleet status page that POSTs to /api/nodes/{mac}/identify.
- Added CSS styling for .node-identify-btn with hover/active states
- Implemented identifyNode() function that sends identify command
- Button only shows for online nodes
- Toast notifications for success/failure feedback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POST /api/nodes/{mac}/identify endpoint with {duration_ms: 5000} body
- Forwards identify message as WebSocket JSON to target node
- Returns 404 if node not connected; 200 on success
- Includes table-driven tests for all edge cases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add led_init() call during firmware initialization in app_main()
- Add led_stop_blink() call on WebSocket disconnect
- LED GPIO configurable via CONFIG_SPAXEL_LED_GPIO (default GPIO8)
- Blink runs in FreeRTOS task at ~5Hz (100ms on/100ms off)
- Any running blink is cancelled when new identify message received
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>