Commit graph

46 commits

Author SHA1 Message Date
jedarden
281bbefb57 feat: complete floor plan dashboard UI
- 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>
2026-04-09 08:37:08 -04:00
jedarden
3da0c32ba3 feat: dashboard PIN change flow
- 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>
2026-04-09 08:05:35 -04:00
jedarden
47e8fa7999 feat: add identify button to fleet status page and 3D view context menu
- 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>
2026-04-09 07:41:18 -04:00
jedarden
519b5cbe09 feat: add Identify context menu to 3D view
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>
2026-04-09 07:31:35 -04:00
jedarden
7559f1964e feat: add Identify button to fleet status page
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>
2026-04-09 07:17:13 -04:00
jedarden
24e652a389 feat: integrate OUI lookup into passive radar AP detection
- Add manufacturer display to AP detection banner
- Show "your router (Manufacturer)" when OUI is known
- Show "your router" as fallback when OUI unknown
- Expand OUI database with more manufacturer entries

The AP detection banner now shows the router manufacturer
when available from OUI lookup, making it easier for users
to identify their router during the onboarding process.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 06:35:44 -04:00
jedarden
636f3efba2 feat: complete anomaly detection & security mode dashboard UI
- Add anomaly.css and sleep.css to dashboard includes
- Add sleep.js for sleep quality monitoring
- Implement analytics API handler (flow, dwell, corridors)
- Add tracks API and tests for time-based data queries
- Add sleep monitor tests
- AnomalyDetector initialized and running in main()
- Anomaly events broadcast via WebSocket to dashboard
- Security mode arm/disarm persists across restarts (learning_state table)
- Learning progress tracking and display
- Alert banner with acknowledge functionality
- All API endpoints wired: /api/anomalies, /api/security/*, /api/analytics/*

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 05:59:54 -04:00
jedarden
bf40673b72 feat: wire anomaly detection & security mode API endpoints
AnomalyDetector is initialized in main() with periodic model updates.
Anomaly events are pushed to dashboard WS as 'alert' messages via
BroadcastAlert callback. Security mode arm/disarm state persists
across restarts via SQLite learning_state table.

Endpoints:
- GET /api/anomalies?since=24h — list recent anomaly events
- POST /api/security/arm — enable security mode
- POST /api/security/disarm — disable security mode
- GET /api/security/status — armed, learning_until, anomaly_count_24h

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 14:36:59 -04:00
jedarden
ff3428fee6 feat: robust WebSocket reconnection with backoff, extrapolation, and visual states
Implements exponential backoff (1s→10s cap) with ±500ms jitter,
blob position extrapolation during disconnects (capped at 2s),
three visual states (silent <5s, dimming 5-30s, modal >30s),
and automatic scene restoration on reconnect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 12:34:35 -04:00
jedarden
97f1eafc6f feat: process buffered events from delta WebSocket updates
Events (zone entries/exits, portal crossings, presence transitions)
were already broadcast immediately via BroadcastEvent, but the
buffered copies included in the 10 Hz delta tick were silently
dropped by handleIncrementalUpdate. Now delta events are processed
through the same handleEventMessage path, with dedup to avoid
double-processing when both immediate and delta copies arrive.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:04:49 -04:00
jedarden
cac25e86e8 feat: implement security mode dashboard UI
- Update learning progress display to show "X of Y days complete" format
- Add last anomaly location info to security dialog stats
- Add CSS styling for anomaly event type in timeline

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:22:00 -04:00
jedarden
80ac99ca7c feat: implement security mode dashboard UI
- Add security status indicator in status bar with mode badge
  (DISARMED / LEARNING / ARMED / ALERT)
- Add arm/disarm toggle button with confirmation dialog
- Add learning period progress bar display
- Add alert banner for anomalies when armed
- Add acknowledge functionality for anomalies
- Integrate with WebSocket for real-time updates
- Add security.css with responsive styles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 10:14:51 -04:00
jedarden
5b24192186 feat: add trigger_state WebSocket message type to /ws/dashboard feed
Broadcasts { type: 'trigger_state', trigger: { id, name, last_fired, enabled } }
on trigger fire, enable, and disable events. Handled in app.js onmessage
and forwarded to window.Automations.updateTriggerState().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 08:41:17 -04:00
jedarden
93735f70bf feat: wire alert broadcasts for anomaly detections and security mode changes
- Connect anomaly detector callbacks to BroadcastAlert for dashboard alerts
- Add security mode change callback to broadcast typed alerts
- Add blob appeared/disappeared callbacks to Tracker
- Add alert tracking state (alerts Map, unacknowledgedCount) in dashboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 06:57:23 -04:00
jedarden
757d7240dc feat: implement snapshot-on-connect + incremental update protocol for dashboard WebSocket
- Hub sends full snapshot (type=snapshot) on new client connect before adding
  to broadcast list, preventing race with delta messages
- tickDelta at 10 Hz computes byte-level diffs of cached JSON fields, broadcasts
  only changed fields with no type field
- Dashboard sets awaitingSnapshot on WS open, drops incremental updates until
  snapshot received, rebuilds full state from snapshot
- Fix zone snapshot building (nil→ok check, SizeX fields)
- Remove unused broadcastBLEScan function
- Add drainSnapshot helper and fix TestHub_LinkEvents to account for snapshot
- Add TestHub_SnapshotOnConnect, TestHub_SnapshotBeforeDelta, TestHub_DeltaOmitsTypeField

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 22:00:36 -04:00
jedarden
e74834a3bf feat: implement webhook action firing & fault tolerance for automations
Backend: HTTP client with 5s timeout, fire-and-forget webhook delivery,
4xx disables trigger with error message, 5xx/timeout increments error count,
test endpoint, enable/disable endpoints, webhook_log audit table,
WebSocket alert broadcasting on trigger errors.

Dashboard: error badge on trigger cards, Test Webhook button, webhook log
view, Re-enable button, real-time error alerts via WebSocket.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 21:39:51 -04:00
jedarden
22b745f274 feat: webhook action firing & fault tolerance for automations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 20:29:53 -04:00
jedarden
3781ab7f86 feat: implement BLE device discovery & registration dashboard panel
Implements a comprehensive 'People & Devices' panel for BLE device management:

Frontend (dashboard/js/ble-panel.js, dashboard/css/ble-panel.css):
- Device list sorted by sighting frequency (rssi_count)
- Registration modal with label, person assignment, color picker, device type
- Auto-type hints with icons (iPhone, Apple Watch, Fitbit, Tile, AirTag)
- Pre-registration form for manual MAC address entry
- Unregistered count badge on panel toggle
- Device details modal with sighting history

Backend (mothership/internal/ble/handler.go):
- GET /api/ble/devices with registered/discovered filters and hours parameter
- PUT /api/ble/devices/{mac} for updates (label, device_type, person_id)
- GET /api/ble/devices/{mac}/history for sighting timeline
- POST /api/ble/devices/preregister for manual device entry
- GET /api/people and POST /api/people for person management

Database (mothership/internal/ble/registry.go):
- Enhanced ble_devices table with person_id, device_type, manufacturer fields
- ble_device_sightings table for history timeline
- Auto-detection of device types from manufacturer data (Apple, Fitbit, Garmin, Tile)
- RSSI tracking and averaging

Integration (dashboard/index.html, mothership/cmd/mothership/main.go):
- BLE panel button with unregistered badge in dashboard
- BLE registry wired to dashboard hub for WebSocket broadcasts
- 5-second ticker broadcasts device state to connected clients

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 15:21:11 -04:00
jedarden
374b61a559 feat: implement BLE address rotation detection & identity continuity
Backend (mothership/ble/):
- RotationDetector with manufacturer data fingerprinting, time+RSSI proximity
- ble_device_aliases table for tracking rotated MAC addresses
- Identity matcher integration with alias resolution for blob-to-device scoring
- 5-minute grace period fallback when rotation is unresolved
- REST API: GET /api/ble/devices/{mac}/aliases, POST /api/ble/merge, POST /api/ble/split

Dashboard UI (dashboard/js/):
- Rotation icon indicator (🔄) in BLE device registry
- Manual merge/split UI with confirmation dialog
- Alias history expandable in device detail panel
- Possible rotations section with match confidence

Acceptance:
- Identity continuity across address rotation with >90% precision
- No duplicate person tracks created on rotation event
- Alias history queryable via GET /api/ble/devices/{mac}/aliases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 14:33:27 -04:00
jedarden
d2e5b4d4a0 feat: implement passive radar auto-detection of router AP
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>
2026-04-06 14:03:03 -04:00
jedarden
34a2247fd9 feat: implement detection explainability overlay with per-link contributions, Fresnel visualization, and BLE match display
- Add explainability.js module with sidebar panel, X-ray overlay, Fresnel zone rendering
- Add explainability handler with /api/explain/{blobID} endpoint
- Fix viz3d.js CONFIG reference by adding FRESNEL_CONFIG constant
- Integrate explainability into fusion engine and ingestion server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 13:31:17 -04:00
jedarden
e83b54a9ec feat: implement dashboard PIN authentication and session management
Backend (mothership/internal/auth/):
- SQLite auth table with pin_bcrypt and install_secret (singleton row)
- GET /api/auth/status — return {pin_configured: bool}
- POST /api/auth/setup — sets PIN (bcrypt cost 12) on first run only
- POST /api/auth/login — verifies PIN, issues session cookie (7-day expiry)
- POST /api/auth/logout — clears cookie and deletes session from SQLite
- Session middleware: all /api/* and /ws/* require valid session
- Rolling window: extends session by 7 days if within 24h of expiry
- Install secret generation for node token derivation

Dashboard (dashboard/js/auth.js):
- On load: GET /api/auth/status check
- First-run setup page: enter PIN + confirm PIN → POST /api/auth/setup → reload
- Login page: shown on 401; PIN entry → POST /api/auth/login → reload
- Logout button in settings panel → POST /api/auth/logout → redirect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 13:16:04 -04:00
jedarden
27755fc98d feat: implement dashboard activity timeline view
Add comprehensive activity timeline view for the Spaxel dashboard:

- Timeline sidebar with scrollable chronological event list (newest first)
- Event types with distinct icons/colors: zone_entry/exit (green/orange),
  portal_crossing (blue), anomaly/security_alert (red), learning_milestone (purple), system (grey)
- Each event shows: timestamp, description, person name, zone name
- Click event → jump to that moment in replay mode
- Filter bar: filter by person, zone, event type, time range (today/7d/30d)
- Search box with debounced text filter (300ms)
- Inline feedback (thumbs up/down) on presence detection events
- POST /api/feedback endpoint for feedback submission
- GET /api/events endpoint with pagination and filtering
- Live updates: 'event' messages from WebSocket feed
- New events prepend without layout shift using DOM insertion
- Loading states, empty state, and "load more" pagination

Acceptance criteria met:
- 200 events render within 200ms
- New events prepend without layout shift
- Clicking event seeks replay to that moment
- Feedback shows toast confirmation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 12:01:19 -04:00
jedarden
bfa3e6f2b2 feat: expand dashboard WebSocket feed with events, alerts, BLE, triggers, and system health
- Add BroadcastEvent for presence transitions, zone entries/exits, portal crossings
- Add BroadcastAlert for anomaly detections and security mode triggers
- Add BroadcastBLEScan for BLE device list updates (5s interval)
- Add BroadcastTriggerState for automation trigger state changes
- Add BroadcastSystemHealth for periodic system stats (60s interval)
- Add BLEState, TriggerState, and SystemHealthProvider interfaces
- Update hub.Run with new tickers for BLE (5s) and system health (60s)
- Update dashboard app.js with handlers for new message types
- Add bleDevices map to state for BLE device tracking
- Log unhandled message types for future debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 10:18:04 -04:00
jedarden
c424104582 feat: build dashboard panel/modal/sidebar UI framework
Implemented a comprehensive panel framework for the Spaxel dashboard to
support Phase 6-9 UI work (automation builder, timeline, explainability,
settings, notifications, presence predictions).

- Panel System (dashboard/js/panels.js):
  - Slide-in sidebar (right, 360px) with close button and title
  - Modal overlay (centered, 600px wide) for forms and wizards
  - Toast notification stack (bottom-right) with type variants
  - Panel registry: panels can be opened by name from anywhere

- Route/Mode Navigation (dashboard/js/router.js):
  - Hash-based routing: #live (default), #timeline, #automations, #settings
  - Mode toggle bar in header with active state styling
  - Active mode persisted across page refresh (localStorage)

- State Management (dashboard/js/state.js):
  - Central app state object (nodes, blobs, zones, links, alerts, events)
  - Subscribe/notify pattern for reactive component updates
  - Convenience methods for common operations (updateNode, addEvent, etc.)

- Settings Panel (dashboard/js/settings-panel.js):
  - Motion threshold slider (deltaRMS threshold)
  - Fusion rate selection (5/10/20 Hz)
  - Grid cell size and Fresnel decay rate controls
  - Subcarrier count and baseline time constant settings
  - Notification channel config (Ntfy URL/token, Pushover keys)
  - System info display (version, uptime, detection quality, node count)

- Updated index.html with:
  - CSS/JS includes for panel framework
  - Settings button in status bar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 10:04:40 -04:00
jedarden
118c6b1c9d feat: add new internal packages (events, automation, ble, falldetect, mqtt, notify, prediction, sleep, tracker, zones, analytics) and dashboard modules (anomaly, automations, blepanel, fleet) 2026-04-06 09:48:31 -04:00
jedarden
c75428d488 ci: set VERSION to 0.1.0 for image build 2026-04-06 08:53:25 -04:00
jedarden
14c49cb919 feat(breathing): implement stationary person detection via breathing analysis
Add FFT-based breathing detection with long-dwell presence tracking:

- FFTBreathingDetector: Rolling 30-second buffer, Hann window, FFT analysis
  to detect periodic breathing signals in 0.2-1.0 Hz band
- DwellTracker: State machine with CLEAR → MOTION_DETECTED →
  POSSIBLY_PRESENT → STATIONARY_DETECTED transitions
- Health gating: Detection disabled when link health < 0.7
- Dashboard: Slow-pulsing blue dot for stationary detection with BPM tooltip
- Timeline: Event logging on transition to STATIONARY_DETECTED

Physics: CSI phase oscillates at 2x breathing rate due to round-trip
path length change. 15 BPM breathing → 0.5 Hz CSI phase oscillation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 20:25:17 -04:00
jedarden
f7b9719d1b feat(localization): implement self-improving localization with BLE ground truth
Implement a complete self-improving localization system that uses BLE
RSSI triangulation as ground truth to learn per-link, per-zone weights
for the Fresnel zone fusion engine.

Key components:
- Ground truth sample collection with confidence > 0.7 and distance < 0.5m gates
- Spatial weight learner using online SGD with L2 regularization
- Validation gate that rejects updates without 5% improvement on holdout set
- Bilinear interpolation for smooth weight transitions between zones
- SQLite persistence for weights with 10,000 sample cap per person
- Position accuracy trend visualization in dashboard Accuracy panel

Backend (mothership/internal/localization/):
- groundtruth.go: BLE trilateration provider with Gauss-Newton optimization
- groundtruth_store.go: SQLite storage with weekly accuracy rollups
- spatial_weights.go: SpatialWeightLearner with SGD, validation, interpolation
- weightlearner.go: WeightLearner with error history tracking
- weightstore.go: Weight persistence to SQLite

Frontend (dashboard/js/accuracy.js):
- fetchPositionAccuracy/fetchPositionHistory functions
- drawPositionSparkline for weekly median error trend
- Position accuracy section with median error, trend indicator, sample count

Tests cover:
- Sample collection gates (confidence/distance thresholds)
- SGD weight updates after 100 samples
- Validation gate rejection of adversarial samples
- Bilinear interpolation smoothness
- SQLite sample cap enforcement
- Weight persistence across restarts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 20:11:22 -04:00
jedarden
fb218f5410 feat(learning): complete feedback loop with time-range queries and zone breakdown
- Add GetFeedbackInTimeRange() to query feedback by timestamp for accuracy computation
- Add GetUniqueScopeIDs() to extract unique link/zone/person IDs from feedback
- Update accuracy.go to use the new store methods for proper scope filtering
- Add zone breakdown visualization in accuracy panel with clickable zone items
- Add blob hover tooltips with thumbs up/down feedback buttons in 3D view
- Wire up feedback processor and accuracy computer in main startup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 18:03:45 -04:00
jedarden
20aadb54f0 feat(learning): expose showToast for feedback module integration
Add showToast to SpaxelApp public API so the Feedback module can
display toast notifications when users submit feedback on detections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 16:47:38 -04:00
jedarden
037ac09d9e feat(analytics): implement crowd flow visualization
Add trajectory accumulation, directional flow maps, and dwell time
hotspot visualization for occupancy pattern analysis.

Backend:
- FlowAccumulator records trajectory segments and dwell time in SQLite
- REST endpoints for flow map, dwell heatmap, and detected corridors
- Bresenham rasterization for flow vector aggregation
- Connected component analysis for corridor detection

Frontend:
- Pattern controls in dashboard sidebar (flow, dwell, corridors toggles)
- Time filter dropdown (7d, 30d, all time)
- 3D visualization with ArrowHelper for flow, PlaneGeometry for heatmaps
- Pulsating animation on flow arrows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 15:38:40 -04:00
jedarden
4af8046acd feat(learning): implement detection feedback loop and accuracy tracking
- Add feedback_store.go with SQLite storage for detection feedback and accuracy metrics
- Add feedback_processor.go for background processing of user feedback
- Add accuracy.go for weekly precision/recall/F1 metric computation
- Add handler.go with REST API routes for feedback submission and accuracy retrieval
- Wire learning package into main_phase6.go with background processing
- Add dashboard/js/feedback.js with thumbs-up/down UI components
- Add dashboard/js/accuracy.js with accuracy panel rendering and sparkline trends
- Add comprehensive tests for feedback storage and accuracy computation

Feedback UI provides:
- Thumbs-up/down buttons for detection events
- Feedback form with false positive/negative options
- Missed detection reporting with position/zone selection
- Motivational counter showing improvement from user corrections

Accuracy panel shows:
- Circular gauge with F1 score
- Week-over-week trend sparkline
- Per-zone breakdown of precision/recall
- Total corrections count and improvement percentage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 14:50:36 -04:00
jedarden
bc2c377e0c feat(signal): implement Phase 5 Reliability & Intelligence
Phase 5 deliverables:
- Diurnal adaptive baseline (24-slot hourly vectors, 7-day learning, crossfade, confidence indicator)
- Stationary person detection (breathing band 0.1-0.5 Hz, long-dwell logic with health gating)
- Ambient confidence score (per-link health: SNR, phase stability, packet rate, drift; composite gauge)
- Link weather diagnostics (root-cause suggestions, weekly trends, repositioning advice)
- Baseline persistence (SQLite storage for EMA and diurnal baselines)

Key components:
- signal/diurnal.go: 24-hour baseline slots with cosine crossfade
- signal/breathing.go: 4th-order Butterworth bandpass filter for breathing detection
- signal/ambient.go: Per-link health scoring with weighted composite
- signal/persist.go: SQLite persistence for baselines
- signal/healthpersist.go: Health log aggregation for weekly trends
- diagnostics/linkweather.go: 5 diagnostic rules with actionable advice
- diagnostics/reposition.go: GDOP-based repositioning target computation
- fleet/healer.go: Self-healing fleet with role re-optimization
- dashboard/js/app.js: Quality gauge UI with health polling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 12:16:56 -04:00
jedarden
6294f44411 feat(diagnostics): add health persistence tests and frontend enhancements
- Add comprehensive tests for HealthStore (healthpersist_test.go)
- Add link health panel CSS styles and sparkline visualization
- Add ghost node rendering for repositioning advice in viz3d.js
- Wire up all diagnostic API routes in main.go
- Minor test cleanup in linkweather_test.go

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 12:07:58 -04:00
jedarden
66e640522d feat(signal): add ambient confidence score and link health monitoring
Implements per-link health metrics that gate and weight detection algorithms:

Per-Link Health Metrics (LinkHealthScorer in ambient.go):
- SNR Estimate (40% weight): motion/quiet deltaRMS ratio via log10 mapping
- Phase Stability (30% weight): phase variance with 0.5 rad threshold
- Packet Rate Health (20% weight): actual vs configured rate
- Baseline Drift (10% weight): hourly normalized L2 change

Gating Effects:
- BreathingDetector: disabled when health_score < 0.7
- FusionEngine: link contributions weighted by health_score

Dashboard Visualization:
- 3D link line color: green (1.0) → yellow (0.5) → red (0.0)
- 3D link line thickness: 2px (>0.7), 1px (0.4-0.7), 0.5px (<0.4)
- System-wide Detection Quality gauge in header
- Link Health panel with per-metric breakdown and sparklines

API: GET /api/links returns health_score and health_details for each link

Tests:
- Health score computation with weighted sub-metrics
- SNR mapping: SNR=100 → 1.0, SNR=10 → 0.5
- Phase stability: variance=0 → 1.0, variance=0.5 → 0.0
- Breathing health gating at 0.7 threshold
- Fusion engine link weight verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 01:41:43 -04:00
jedarden
90e230f9d9 feat(dashboard): complete Phase 4 onboarding & OTA system
Interactive onboarding wizard:
- 8-step Web Serial-based provisioning flow
- Firmware flashing via esp-web-install-button (CDN)
- Live CSI waveform feedback during guided calibration
- Server-side provisioning with client-side fallback
- Serial JSON response handling with error mapping
- Post-calibration reinforcement card with link count

OTA firmware management:
- Firmware list with SHA-256 hashes and size display
- Per-node progress tracking (idle/pending/downloading/rebooting/verified/failed/rollback)
- Rolling update orchestration via REST API
- Status bar button with state indicators (normal/in-progress/has-update)
- Node list badges for OTA status and rollback warnings

Guided troubleshooting:
- First-time feature tooltips with 8s auto-dismiss
- Sequential tooltip tour triggered on first node connection
- Node offline cards with step-by-step recovery instructions
- Factory reset instructions modal
- Client-side link health check (60s no-frame threshold)
- Captive portal recovery documentation

Exit criteria: New ESP32-S3 from unboxed to streaming CSI in under 5 minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 21:21:55 -04:00
jedarden
7b325703bd feat(dashboard): interactive 3D node placement with real-time GDOP coverage overlay
Adds TransformControls for dragging nodes in the 3D scene, a room dimension
editor (width/depth/height), a GDOP (Geometric Dilution of Precision) coverage
overlay on the ground plane that updates in real-time during node drag, virtual
node support for planning optimal placement before hardware purchase, and REST
API integration to persist positions and room config to the mothership.

Backend adds PUT /api/nodes/{mac}/position, POST /api/nodes/virtual,
DELETE /api/nodes/{mac}, PUT /api/room endpoints. Also wires OTA status
handler and improves firmware manifest to use actual latest binary filename.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 09:25:44 -04:00
jedarden
570e5eec41 feat(dashboard): guided troubleshooting and first-time UX
Add troubleshooting infrastructure for non-technical users:

- TroubleshootManager: node offline cards with stepped recovery
  guidance, factory reset modal, and detection quality banners
- TooltipManager: first-time feature tooltips with localStorage
  persistence, auto-dismiss, and sequential tour
- Onboarding failure guidance: human-readable error messages for
  browser compatibility, USB connection, WiFi provisioning, and
  node detection failures
- Post-calibration reinforcement card with summary and next steps
- Client-side link health check with auto-recovery
- CSS for offline cards, tooltips, quality banners, and modals
- Script tags wired in index.html for troubleshoot.js and tooltips.js
- 30 tests covering all troubleshooting and tooltip functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 04:19:06 -04:00
jedarden
1b0e7ea2b4 fix(dashboard): fix onboarding wizard test failures
- Fix WebSocket mock to use factory function so resetAllMocks doesn't
  break it (state.ws.close is not a function errors)
- Fix TextEncoderStream mock to provide functional readable/writable
  for pipeTo (needed by provisioning serial send tests)
- Fix flash_firmware test to check wizard-nav for "Skip Flashing"
  button instead of wizard-content
- Fix provisionAndSend "no port" test to use mockResolvedValue
  instead of mockResolvedValueOnce so both primary and fallback
  paths fail consistently

All 60 tests now pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 04:01:20 -04:00
jedarden
5ddb8973e2 feat(dashboard): interactive onboarding wizard for ESP32-S3 node provisioning
Web Serial-based wizard that takes a non-technical user from unboxed
ESP32-S3 to streaming CSI in under 5 minutes. 8-step state machine:
browser check → connect → flash firmware (esp-web-tools) → provision
WiFi → detect node → guided calibration → placement guidance → complete.

Includes sessionStorage persistence for resumability across page refreshes,
live CSI waveform during calibration, human-friendly error messages for
all failure modes, and comprehensive Jest test coverage (34 tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 02:36:58 -04:00
jedarden
75edd8339a feat(dashboard): presence panel with per-link motion indicators and deltaRMS time series
Add 500ms periodic presence_update broadcast from the dashboard hub with
per-link motion state (is_motion, delta_rms, confidence). Surface this in
a new Presence panel on the dashboard with coloured dot indicators
(green=clear, amber=motion, red=high-confidence) and deltaRMS values.
Includes a rolling 10s Canvas 2D line chart of deltaRMS with a threshold
line at 0.02 for the selected link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 23:49:08 -04:00
jedarden
bcd19ad756 feat(dashboard): 3D spatial visualization with humanoid SkinnedMesh figures
Implements plan item 17 — full Three.js Phase 3 visualization layer:

- Room bounds: floor, ceiling, semi-transparent walls and wireframe edges
  built from registry_state room config (width/depth/height/origin)
- Floor plan texture: upload any image via status-bar button; mapped to
  ground plane via THREE.TextureLoader
- Humanoid figures: SkinnedMesh + AnimationMixer with 13-bone skeleton;
  four AnimationClip postures (standing, walking, seated, lying); smooth
  0.35 s crossfade transitions; walking speed scales animation timeScale;
  figures orient in direction of travel
- Vertical pillar anchors: line from floor to ceiling at each blob position
- Footprint trails: floor-level Line geometry following blob.trail history
- Node meshes: OctahedronGeometry at registry node 3-D positions; link
  lines redrawn whenever link_active/inactive events arrive
- View presets: 3D perspective, top-down orthographic, first-person follow
  (lerps camera to track first active blob)
- WebSocket: handles registry_state, loc_update, link_inactive message types
  newly routed through handleJSONMessage; existing CSI/motion pipeline intact

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 00:26:25 -04:00
jedarden
fb691904c6 feat(dashboard): per-link motion presence indicator with amplitude time series
- 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>
2026-03-26 22:55:33 -04:00
jedarden
de424a1f63 feat(mothership): complete Phase 2 signal processing & detection
- Dashboard presence indicator: per-link MOTION/CLEAR badges with global
  status bar indicator, motion_state WebSocket messages, amplitude chart
- CSI recording buffer: disk-backed circular buffer (replay/store.go) with
  magic-tagged binary format, wrap/eviction, 360 MB default (~48 h at 20 Hz)
- Adaptive sensing rate: RateController ramps nodes to 20 Hz on motion,
  drops to 2 Hz after 10 s idle; wires to SendConfigToMAC over WebSocket
- Fix: alias internal/signal as sigproc to avoid conflict with os/signal
- Fix: add GetAllMotionStates() to MockIngestionState in dashboard tests

All tests pass (signal, ingestion, replay, dashboard).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:27:24 -04:00
jedarden
8230ef4222 feat(dashboard): web dashboard skeleton with Three.js 3D scene and CSI visualization
- Static HTML/JS dashboard served by mothership at /
- Three.js 3D scene with ground grid, OrbitControls (pan/zoom/rotate)
- WebSocket connection at /ws/dashboard for real-time CSI streaming
- Binary CSI frame parsing (24-byte header + I/Q payload)
- Amplitude bar chart (64 subcarriers) as 2D Canvas overlay
- Node/link panels with live status and click-to-select
- Dashboard Go package with Hub for client broadcasting
- Ingestion server broadcasts CSI frames and node events to dashboard
- 5 new tests for dashboard hub operations

Complete: 3D scene, WebSocket, amplitude chart, node/link panels
Remaining: Docker packaging (Phase 1 final item)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 07:40:53 -04:00