The dashboard tracked active calls purely by START/END events, so any START without a matching END accumulated forever. Under heavy same-timeslot contention this is expected: HBlink3's per-slot state turns over rapidly, and its stream trimmer only emits an END for whichever stream currently owns the slot -- a stream that was superseded never gets a matching END. Real RF calls also drop mid-stream (loss of sync, hotspot reboot), with no terminator. Add a stream reaper on both sides: the backend drops active streams >30s old (STREAM_STALE), and the browser ages out ST.active entries on the same threshold in its 1s tick. Normal calls still clear instantly on END; only phantoms are swept. Found via the repeater simulator, which left 57 phantom "active" streams after a 172-call run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
HBlink3 Dashboard
A real-time web dashboard for HBlink3, in the spirit of the old HBmonitor (same tables and information) but with a modern dark UI and a far more efficient data path. It is a separate program from the HBlink3 core.
It connects to HBlink3's reporting feed, keeps the display state, and pushes live JSON deltas to the browser over a WebSocket. The browser renders the tables and ticks the duration/uptime counters itself — no full-page or full-table refreshes, and no pickle on the wire.
What it shows
- Master Systems — each master and its connected repeaters (ID, callsign, location, IP, uptime, frequency, colorcode, slots) with the live call on each timeslot (source → destination, color-coded by direction).
- Peer Systems — outbound peer connections with health (connection state, pings sent/ackd/lost) and live per-timeslot calls.
- OpenBridge Systems — network ID, target, and active streams.
- Conference Bridges — each bridge's members: timeslot, talkgroup, connected/disconnected state, timeout countdown, and on/off trigger talkgroups.
- Call Log — a running log of call starts and ends.
Install
cd dashboard
python3 -m venv venv && source venv/bin/activate # or reuse the HBlink3 venv
pip install -r requirements.txt
cp config_sample.py config.py # then edit config.py
python server.py # or, from the repo root: python run_dashboard.py
Open http://<host>:8080.
Configuration (config.py)
HBLINK_IP/HBLINK_PORT— HBlink3's reporting feed (the[REPORTS]section ofhblink.cfg:REPORT_PORT, default 4321).WEB_HOST/WEB_PORT— where the dashboard listens.PATH/*_FILE— alias files mapping DMR IDs to callsigns/talkgroup names (the same files HBlink3 uses; pointPATHat HBlink3's directory to share them).REPORT_NAME,LOG_LINES— branding and call-log length.
HBlink3 side
In hblink.cfg, under [REPORTS]:
REPORT: TrueREPORT_PORTmust match the dashboard'sHBLINK_PORTREPORT_CLIENTSmust include the dashboard host's IP (or*)REPORT_INTERVALsets how often the systems/bridge snapshot is refreshed. Live calls are pushed instantly; connection/peer-state changes appear on the next snapshot, so10is a good value for dashboard use.
Notes
- This replaces the old HBmonitor. HBlink3's reporting feed is now newline-delimited JSON, which HBmonitor does not understand.
- The dashboard depends on FastAPI + Uvicorn; the HBlink3 core itself remains stdlib-only.