Feat: add SLM live monitoring improvements #60
Reference in New Issue
Block a user
Delete Branch "feat/slm-live-monitor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The SLM live view now consumes SLMM's shared DOD /monitor feed instead of the per-client DRD /stream. This fixes the single-connection contention (many viewers share one device feed) and finally puts L1/L10 in the live chart (DRD couldn't carry percentiles). - New WS proxy handler /api/slmm/{unit}/monitor -> SLMM /api/nl43/{unit}/monitor. Uses asyncio.wait(FIRST_COMPLETED) + cancel-sibling instead of gather(), so it doesn't leave a task sending into a closed socket ("Unexpected ASGI message after close"). - Live view JS points at /monitor; onmessage reflects feed_status and ignores heartbeat / unreachable frames so they don't blank the cards or zero-spike the chart. Adds a small Live/Device-offline badge. Still on the old /live (DRD): the dashboard live tile (sound_level_meters.html) — next slice. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The /monitor WS proxy cancelled its sibling task on disconnect but then `except Exception` failed to swallow the resulting CancelledError (a BaseException), so stopping the stream raised "Exception in ASGI application". It also only awaited the pending task, leaving the done task's WebSocketDisconnect unretrieved ("Task exception was never retrieved"). Await all tasks and catch (CancelledError, Exception). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Adds a "Live Monitoring (keepalive)" card listing each SLMM device with its monitor_enabled state and an Enable/Disable toggle. Reads from /api/slmm/roster (now includes monitor_enabled) and POSTs to /api/slmm/{unit}/monitor/{start,stop}, which persist the flag in SLMM (survives restarts; auto-started on boot). Shows a reachability dot + 24/7 ON/OFF badge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>On opening the live view, fetch GET /api/slmm/{unit}/history?hours=2 and seed the chart with the recent trend BEFORE connecting the live socket, so it opens with context instead of blank. Live frames then append in order. - backfillChart() populates all four series (Lp/Leq/L1/L10) from the trail. - initLiveDataStream is async and awaits the backfill before opening the WS. - Chart rolling window raised 60 -> 600 points so the ~2h backfill (1/min) isn't immediately shifted out. - Trail timestamps are naive UTC -> append 'Z' so they localize consistently with the live frames. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>toggleSLMDeployed() and the save-config success path both called htmx.trigger('#slm-list', 'load') guarded only by `typeof htmx !== 'undefined'`. No page actually has a #slm-list element, so htmx resolved the selector to null and called null.dispatchEvent(...) -> "can't access property dispatchEvent, e is null". The deploy POST had already succeeded and the green success message had already rendered, so the user saw both "Unit marked as deployed." and a red error. Guard the trigger on the element existing so it's a harmless no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Live Measurements panel no longer sits blank until you click Start Live Stream: - On open it fills the KPI cards from the cached /status snapshot (lp/leq/lmax/ L1/L10) and backfills the chart from the /history DOD trail — both pure cache reads, no device hit. - Shows measuring state (● Measuring / ■ Stopped) and a freshness stamp ("as of 2:14 PM (12m ago)") that turns amber + "cached" when stale, so a cached value is never mistaken for a live reading. - Polls the cache every 15s while open so the cards stay current without opening a device stream; Start Live Stream takes over (and no longer wipes the backfilled trail). Chart cap raised 60 -> 600 so the 2h backfill isn't truncated. Refresh buttons (on-demand, user-initiated single device read via GET /live, which also updates the cache): - one per device row in the list, and one in the panel header. Spinner while in flight; toast on success/failure; reloads the list so badges + last-check update. Layout fix: the status badge (Measuring/Active/Idle/Benched) was rendered at the top-right of the card, colliding with the absolutely-positioned chart/gear icons. Moved it to the bottom meta row next to "Last check", padded the card content clear of the action icons, and added the refresh icon to that group. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>