Files
hblink3/run_dashboard.py
Cort BuffingtonandClaude Opus 4.8 2836f71ec7 Add HBlink3 dashboard (FastAPI + Uvicorn, modern UI)
A real-time web dashboard for HBlink3 -- a separate program that replaces the old
HBmonitor. It keeps HBmonitor's information and table layout (master systems with
their repeaters, peer systems, OpenBridge systems, conference-bridge state, and a
call log) but borrows HBlink4's modern dark aesthetic and an efficient,
event-driven data path.

How it works:
- dashboard/server.py connects to HBlink3's NDJSON reporting feed, maintains the
  authoritative display state, resolves DMR IDs to callsigns/talkgroup names via
  the shared alias files, and serves a single-page UI plus a WebSocket that pushes
  JSON deltas (and a small REST API at /api/state).
- dashboard/static/dashboard.html renders the tables client-side and ticks the
  uptime / call-duration / bridge-timeout counters in the browser, so there are no
  full-table re-renders and the duration figures update live. Live calls are
  pushed instantly; systems/peer state refreshes on the periodic config snapshot
  (REPORT_INTERVAL).

Efficiency vs HBmonitor: JSON deltas instead of whole-table HTML pushed every
tick; client-side rendering and live counters; no pickle on the wire; server-
computed time deltas so the browser needs no clock sync.

Includes config_sample.py, requirements.txt (FastAPI/Uvicorn/dmr_utils3 -- the
core stays stdlib-only), README, run_dashboard.py launcher, and an
hblink3-dash.service systemd unit. dashboard/config.py is git-ignored.

Verified end-to-end against a live bridge.py: the dashboard ingests the config
and bridge snapshots, resolves a talkgroup alias, and serves the branded SPA;
frontend JS parses clean; the HBlink3 core test suite is unaffected (39 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 13:54:28 -05:00

12 lines
298 B
Python

#!/usr/bin/env python
# Convenience launcher for the HBlink3 dashboard. Equivalent to running
# `python dashboard/server.py`.
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'dashboard'))
import server
if __name__ == '__main__':
server.main()