- Add GET /api/ble/devices to list known devices with filtering
- Add PUT /api/ble/devices/{mac} to set label and assign to person
- Add comprehensive OpenAPI-style godoc comments for all BLE endpoints
- Add table-driven tests for BLE handler endpoints
Endpoints support:
- Filtering by registration status (registered/discovered)
- Time window filtering (hours parameter)
- Device labels and person assignment
- Sighting history per device
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OpenAPI-style godoc comments and comprehensive table-driven tests
for replay endpoints:
- GET /api/replay/sessions - list recording sessions and replay store info
- POST /api/replay/start - start replay at timestamp (speed 1/2/5)
- POST /api/replay/stop - stop replay, return to live
- POST /api/replay/seek - seek within session
- POST /api/replay/tune - update pipeline parameters mid-replay
Improvements:
- Fix writeJSON calls to use proper 3-argument signature
- Add detailed request/response type documentation
- Add mockRecordingStore for isolated unit testing
- Add 12 table-driven test cases covering all endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GET /api/notifications/config to get all delivery channel settings
- POST /api/notifications/config to set channel configurations
- POST /api/notifications/test to send test notifications
- Support for ntfy, pushover, gotify, webhook, and mqtt channel types
- Config validation for each channel type
- Table-driven tests for all endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement GET and POST/PATCH /api/settings endpoints with:
- GET /api/settings: Returns all configurable settings as JSON with
default values merged in for any settings not explicitly set
- POST/PATCH /api/settings: Partial update with merge semantics,
only updating the keys provided in the request body
- SQLite persistence: Settings stored in settings table with
JSON-encoded values, loaded on startup
- Comprehensive validation: All known settings validated with
proper range checks (fusion_rate_hz, grid_cell_m, delta_rms_threshold,
tau_s, fresnel_decay, n_subcarriers, breathing_sensitivity,
motion_threshold, dwell_seconds, vacant_seconds, max_tracked_blobs,
replay_retention_hours, replay_max_mb, security_mode,
events_archive_days)
- OpenAPI-style godoc comments: Documentation for all endpoints
using swagger annotations
- Table-driven tests: Comprehensive test coverage for all
functionality including GET, POST, PATCH, validation,
persistence, and error cases
- Helper utilities: Extracted writeJSON, writeJSONError,
writeJSONData to utils.go for reuse
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
The BLE handler was set but never invoked when BLE messages arrived
from nodes. Replace the TODO with actual bleHandler call so BLE scan
data flows to the registry, enabling the existing 5s ble_scan
WebSocket broadcast to dashboard clients.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BroadcastEventFromDB was using inconsistent field names (timestamp_ms,
type, person) that didn't match the canonical event format (ts, kind,
person_name) expected by handleEventMessage in app.js. This caused
DB-sourced events to render with "undefined" kind/person and "Invalid
Date" timestamps.
Also adds table-driven tests for BroadcastEventFromDB covering zone
entry/exit, portal crossing, anomaly, and minimal events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add TestHub_BroadcastEvent covering all event kinds (zone_entry,
zone_exit, portal_crossing, presence_transition). Also wire
presence_transition broadcasts in the ingestion server when
motion state changes on a link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Connect bleRegistry to the dashboard hub so ble_scan messages are
broadcast every 5s to all connected dashboard clients. Add rssi,
last_seen, and blob_id fields to GetCurrentDevices output to match
the frontend's expected message format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a 5-second ticker in the dashboard hub that broadcasts BLE device
list updates as typed 'ble_scan' messages when devices are present.
The BroadcastBLEScan method and frontend handler already existed but
were never wired up to a periodic timer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify the alert message format {type:'alert', alert:{id,ts,severity,description,acknowledged}}
for anomaly detections and security mode triggers. The BroadcastAlert function and
app.js handler already existed; this adds coverage for critical anomaly, security
mode armed/disarmed, and acknowledged alert scenarios.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up the SQLite Online Backup API streaming endpoint that was
implemented in ad1e17d into the main router.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use modernc.org/sqlite's Online Backup API (NewBackup/Step/Commit)
with in-memory destination and Serialize for consistent hot backups
without temp files. Streams zip directly to HTTP response.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FFT-based breathing rate estimator: 512-sample window at 20Hz, zero-padded to 1024,
dominant peak detection in 0.1-0.5 Hz band (6-30 BPM), 60-second EMA smoothing
- Per-night statistics: breathing_rate_avg, breathing_regularity (CV), anomaly count
- Anomaly detection: 30-day personal average (EMA α=0.05), flags when >25% above baseline
- Morning briefing integration: elevated breathing rate warnings with BPM comparison
- SQLite: breathing_anomaly BOOL and breathing_samples_json columns on sleep_records
- API: GET /api/sleep includes breathing anomaly and personal average fields
- Table-driven tests for FFT accuracy, EMA convergence, anomaly thresholds, regularity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
- BreathingRateEstimator: FFT peak detection on 512-sample (25.6s) phase windows
at 20Hz, zero-padded to 1024 points, 0.1-0.5 Hz band (6-30 BPM), 60s EMA smoothing
- BreathingAnomalyTracker: per-person 30-day rolling EMA (α=0.05), flags elevated
breathing at >25% above personal average
- ComputeBreathingRegularity: coefficient of variation (std/mean) with regular/normal/irregular labels
- Migration 008: add breathing_anomaly BOOL and breathing_samples_json TEXT to sleep_records
- Integration: anomaly check in GenerateMorningReports, anomaly data in report/metrics/handler JSON
- Table-driven tests: synthetic 15/12/20 BPM signals, circular buffer, noise, EMA convergence,
anomaly threshold boundary cases, JSON round-trip, regularity CV computation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Phase 5→6 merge left garbled duplicate portal API code and
missing closing braces. Fixed the zones PUT handler closure, added
missing zones DELETE handler, cleaned up duplicate portal code, and
replaced non-existent GetZoneName() calls with GetZone().Name lookups.
The phase6 build tag and Phase 5 main.go.bak were already removed
in prior work — this commit fixes the remaining compilation errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Route test requests through chi router instead of calling handlers directly
- Fix weekday test to use correct day mapping
- Use context cancellation for timeout test instead of long sleep
- Move mockServer.Close() after assertions to prevent goroutine leak
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use time.Now().In(m.tz) instead of time.Now() in reconcileOccupancy
to correctly compute midnight in the configured timezone
- Fix ReconcileTick to only mark reconciled on exact blob count match
(diff==0), keeping diff==1 as uncertain per spec
- Fix timestamp units consistency (UnixNano → UnixMilli) in crossing
event recording and retrieval
- Fix reconciliation query to use from_zone/to_zone columns
- Reset m.reconciled=false in tests that create uncertain occupancy
after manager construction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- HTTP client with 5s timeout, fire-and-forget webhook delivery
- Payload schema: {trigger_id, trigger_name, condition, blob_id, person, position, zone, dwell_s, timestamp_ms}
- 4xx response: disable trigger, set error_message, push WS alert to dashboard
- 5xx/timeout: log warning, increment error_count, do NOT disable
- error_count resets on first 2xx response
- POST /api/triggers/{id}/test endpoint with synthetic payload
- POST /api/triggers/{id}/enable clears error state and re-enables
- GET /api/triggers/{id}/webhook-log for last N firings
- Audit log via webhook_log table (migration_007)
Dashboard:
- Error badge (ERR) on trigger cards when error_message is set
- Disabled badge when trigger disabled due to 4xx
- Warning badge for transient error_count > 0
- Test Webhook button with real-time response display
- Webhook Log button showing last N firings
- Re-enable button to clear error state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>