Eliminates the manual `scripts/record-baseline.py` ritual:
REST endpoints
GET /api/v1/baseline — current per-node baseline +
last_written_sec_ago + calibration_status
POST /api/v1/baseline/calibrate — start a background capture, optional
JSON body { duration_sec, trim_sec,
clean_window_sec, out }. Returns
immediately; status transitions
idle → running → complete | error: ...
Auto-recalibrate background task
Watches the live classifier. When motion_level=="absent" and CV<0.08 for
--auto-recalibrate-quiet-sec (default 1800 = 30 min) AND the last write
is older than --auto-recalibrate-min-age-sec (default 3600 = 1h),
silently re-runs the capture and live-reloads the override map. No
operator action needed.
Implementation
capture_baseline_to_disk() — in-process port of record-baseline.py:
trim head/tail, scan windows for lowest-
CV chunk, compute full-broadband stats,
write baseline.json, hot-reload override.
BASELINE_BUS — broadcast bus carrying every sensing_update
JSON so the capture can read live frames
without re-binding any sockets.
BASELINE_LAST_WRITTEN — SystemTime tracker for the cool-down.
BASELINE_CALIBRATION_STATUS — status string for the REST endpoint.
Verified live: POST /api/v1/baseline/calibrate (5 s test window) ->
capture wrote `/tmp/test_baseline.json` with n_samples=86 per node,
override hot-reloaded (visible via GET /api/v1/baseline). Real baseline
restored on next server restart from data/baseline.json.