- JavaScript 42.3%
- CSS 29.9%
- TypeScript 27.4%
- Dockerfile 0.3%
- HTML 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docs | ||
| scripts | ||
| server | ||
| src | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| CHANGELOG.md | ||
| compose.broadcastify.yaml | ||
| compose.yaml | ||
| config.example.json | ||
| CONTRIBUTING.md | ||
| Dockerfile | ||
| index.html | ||
| LICENSE | ||
| NOTICE | ||
| ossscanner-verify.txt | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| tsconfig.json | ||
Trunk Fleet Monitor
Public beta — v2.0.3
A self-hosted, read-only dashboard for compatible Trunk Recorder Pro nodes, radio activity, recorder health, and optional Broadcastify listener statistics.
- Live demo: https://trp.renfrewcountyscanner.com/
- Release image:
git.uberplex.ca/renfrewcountyscanner/trunk-fleet-monitor:v2.0.3
The Overview page shows fleet health and current Broadcastify listener counts. The Listeners page provides five-minute history, averages, peaks, and charts. The monitor never plays, proxies, stores, or archives audio and cannot start, stop, or configure recorders.
Screenshots
Quick start
Requires Docker Engine with the Compose plugin and network access from the container to a compatible recorder.
cp config.example.json config.json
# Edit config.json with a reachable recorder URL.
docker compose up -d --build
Open http://localhost:8081. The example hostname is deliberately nonfunctional. Inside Docker, localhost means the monitor container. Set APP_PORT to change the published host port.
The Setup page in the dashboard provides configuration and access guidance. Configuration remains file-based: the browser does not write server settings. Keep actual settings in the ignored config.json and commit only fictional examples.
Configure nodes and Broadcastify
A node is a recorder instance. Add a stable ID, display name, and HTTP/HTTPS origin to config.json. Up to 16 enabled nodes are supported. Systems, channels, talkgroups, SDR assignments, and plugins remain configured in the recorder and are discovered by the monitor.
Broadcastify is optional. Enable it in the settings, add feed IDs and labels, and provide credentials through Docker secrets or host-only secret files. Listener history is stored in the data volume for 30 days. Never commit credentials, private recorder URLs, caches, logs, or deployment files.
See configuration, recorder setup, deployment, and troubleshooting.
Compatibility, privacy, and limits
This release consumes the Trunk Recorder Pro JSON WebSocket protocol at /api/ws. Radio analytics additionally require read-only radioQuery and call-outcome statsQuery capabilities. Other recorder distributions and unsupported Pro versions are not guaranteed to work; report the recorder version when opening an issue.
The viewer has no built-in login. Protect it with a reverse proxy, VPN, firewall, or private network before sharing it. Apply the same access control to HTML, API, and WebSocket routes. Upstream recorder authentication is not implemented.
Recorder history is bounded in memory. Missing observations remain unknown rather than zero. The service is intentionally read-only and has no audio archive.
Release and development
The version below the title comes from package.json; the build ID is generated from application source. Run npm ci, npm test, and npm run build. Browser checks use Playwright separately. The public release tag is v2.0.3-public; the previous v2.0.0 image and private deployment snapshot are rollback points.
See changelog, roadmap, security reporting, and contributing.
License
GPL-3.0-or-later. See LICENSE and NOTICE.
Emergency button alerts
Fleet Monitor subscribes to both platform and emergency on each recorder's /api/ws. Recorders must include the browser bridge that emits Output::Topic { topic: "emergency", ... }; Discord/plugin delivery alone does not supply these browser events. See docs/emergencies.md for the wire format and verification steps.
New emergency events show a full-screen red Emergency Button alert on any dashboard page. It shows the node, system, talkgroup, radio, source and timestamp. Dismiss it immediately or let it close after ten seconds. Each new event replaces the current overlay and restarts its timer. Reduced-motion settings disable the pulse. Existing history is not replayed as new alerts when opening or reconnecting the dashboard.
The compact Overview history and Emergencies tab retain up to 200 independent events per node, with node/system filters. Repeated events with identical fields remain distinct. History survives overlay dismissal and recorder reconnections, but is held in monitor memory and clears when the monitor process restarts. No audio or recorder commands are introduced.

