docs: refresh for the SERVER/OUTBOUND rename, OBP_BRIDGES, and Unix-socket feed

Documentation audit for the recent changes:
  * MODE terminology MASTER->SERVER, PEER/CLIENT->OUTBOUND corrected across
    README, INSTALL, CONFIGURING, ACLS, and the dashboard docs (the code only
    accepts SERVER/OUTBOUND/OPENBRIDGE, so the old names in docs were wrong).
  * README gains a top-of-file breaking-change warning (OBP routing moved to
    OBP_BRIDGES; system-mode rename) with a pointer to the migration tool.
  * CONFIGURING documents REPORT_TRANSPORT/REPORT_SOCKET (Unix-socket feed) and
    a "Migrating from the old inline form" section for tools/migrate_obp_rules.py.
  * dashboard/README documents HBLINK_TRANSPORT/HBLINK_SOCKET and corrects the
    stale "changes appear on the next snapshot" claim (connect/disconnect are
    granular pushes now).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cort BuffingtonandClaude Opus 4.8 committed 2026-07-12 13:42:08 -05:00
1 parent b43ea79c48
commit a3e99a2da9
6 files changed
+59 -32

No files matched your search

+4 -4
View File
@@ -79,7 +79,7 @@ HBlink3 applies four kinds of ACL. Each is a separate config key.
| Key | Gates | Value domain | Notes |
|-----|-------|--------------|-------|
| `REG_ACL` | **Repeater/peer registration** (login) | peer IDs, `1 … 4294967295` | Only meaningful on **server (master)** systems. Peers/OpenBridge don't register. **Always enforced** — see §5. |
| `REG_ACL` | **Repeater/peer registration** (login) | peer IDs, `1 … 4294967295` | Only meaningful on **SERVER** systems. Outbound/OpenBridge links don't accept registrations. **Always enforced** — see §5. |
| `SUB_ACL` | **Subscriber** (the source radio ID of a call) | subscriber IDs, `1 … 16776415` | Applied to every voice/data stream. |
| `TGID_TS1_ACL` | **Destination talkgroup on Timeslot 1** | talkgroup IDs, `1 … 16776415` | |
| `TGID_TS2_ACL` | **Destination talkgroup on Timeslot 2** | talkgroup IDs, `1 … 16776415` | |
@@ -200,11 +200,11 @@ TGID_TS1_ACL: PERMIT:2,9,3120
TGID_TS2_ACL: PERMIT:3120,31205
```
**Registration control on a master.** Accept only two specific repeater IDs onto
this master; reject all other login attempts:
**Registration control on a server.** Accept only two specific repeater IDs onto
this server; reject all other login attempts:
```ini
[MASTER-1]
[SERVER-1]
MODE: SERVER
REG_ACL: PERMIT:311111,311222
```
+20 -6
View File
@@ -4,7 +4,7 @@ HBlink3's conference bridge (`bridge.py`) is driven by two files:
| File | What it defines |
|---|---|
| `hblink.cfg` | The program itself: global timers, reporting, logging, alias lookups, and one stanza per **system** (a Server you host, a Client you dial out as, or an OpenBridge link). |
| `hblink.cfg` | The program itself: global timers, reporting, logging, alias lookups, and one stanza per **system** (a Server you host, an Outbound system you dial out as, or an OpenBridge link). |
| `rules.py` | The **routing**: which systems talk to which, on what timeslot/talkgroup, and the talkgroup triggers/timers that turn bridges on and off. |
This document is the full field reference. The sample files (`hblink-SAMPLE.cfg`, `rules_SAMPLE.py`) carry only terse inline notes and point back here.
@@ -22,12 +22,12 @@ INI format (`configparser`). Section names in `[BRACKETS]`; `KEY: value` pairs.
| Field | Meaning |
|---|---|
| `PATH` | Working directory for runtime files. `./` (the program's own directory) is normal. |
| `PING_TIME` | Seconds between keepalive pings on Server/Client connections. |
| `PING_TIME` | Seconds between keepalive pings on Server and Outbound connections. |
| `MAX_MISSED` | Missed pings before a connection is declared dead and torn down. |
| `PING_LOSS_WINDOW` | Optional (default `5`, range `1`–`60`). Minutes over which the dashboard measures each repeater's **ping loss** — the share of expected keepalive pings that went missing. Larger = smoother / longer memory. Surfaces a repeater that stays connected but has a lossy link (choppy audio). A repeater that merely pings less often is not counted as lossy. |
| `PING_LOSS_WARN` | Optional (default `5`). Ping-loss **percent** at or above which the dashboard turns a repeater's callsign gold. `0` disables the flag. |
| `USE_ACL` | `True`/`False` top-level on/off switch for the **global** ACLs below. System-level ACLs are independent of this. |
| `REG_ACL` | Registration ACL — which Client **radio IDs** may log in to any Server you host. ACL syntax below. |
| `REG_ACL` | Registration ACL — which **repeater radio IDs** may log in to any Server you host. ACL syntax below. |
| `SUB_ACL` | Subscriber ACL — which **subscriber IDs** (the person keying up) may pass traffic, globally. |
| `TGID_TS1_ACL` / `TGID_TS2_ACL` | Talkgroup ACLs applied to timeslot 1 / timeslot 2 traffic, globally. |
@@ -42,7 +42,7 @@ DENY:1-5,3120101 # block the range 1–5 and the single ID 3120101
PERMIT:3100-3199,9 # allow only this range and ID 9; deny everything else
```
A global ACL and a system ACL both apply — traffic must pass **both**. Registration ACLs are only meaningful for `SERVER` systems (a Client or OpenBridge link never registers). See **[ACLS.md](ACLS.md)** for the full ACL model — PERMIT/DENY precedence, how ranges are matched, and worked examples.
A global ACL and a system ACL both apply — traffic must pass **both**. Registration ACLs are only meaningful for `SERVER` systems (an Outbound or OpenBridge link never accepts registrations). See **[ACLS.md](ACLS.md)** for the full ACL model — PERMIT/DENY precedence, how ranges are matched, and worked examples.
## `[REPORTS]`
@@ -52,8 +52,12 @@ Feeds the real-time dashboard. See [`dashboard/`](dashboard/).
|---|---|
| `REPORT` | `True`/`False` — emit the event stream at all. |
| `REPORT_INTERVAL` | Seconds between periodic status reports. |
| `REPORT_PORT` | TCP port the report service listens on. |
| `REPORT_CLIENTS` | Comma-separated client IPs allowed to connect (e.g. `127.0.0.1`). |
| `REPORT_TRANSPORT` | Optional (default `tcp`). `tcp` = listen on a TCP port (dashboard may be remote); `unix` = listen on a local Unix-domain socket instead. A same-box dashboard on a Unix socket can't be broken by a NIC flap or connection-tracking eviction, so use `unix` when the dashboard runs on the same host. |
| `REPORT_PORT` | TCP port the report service listens on (when `REPORT_TRANSPORT` = `tcp`). |
| `REPORT_SOCKET` | Filesystem path for the listening socket (when `REPORT_TRANSPORT` = `unix`), e.g. `/tmp/hblink3-report.sock`. Access is governed by filesystem permissions; `REPORT_CLIENTS` is not used on a Unix socket. |
| `REPORT_CLIENTS` | Comma-separated client IPs allowed to connect (e.g. `127.0.0.1`) — TCP only. |
> The dashboard has matching `HBLINK_TRANSPORT` (`tcp`/`unix`) and `HBLINK_SOCKET` settings — see [dashboard/README.md](dashboard/README.md). Point the dashboard at the same transport the daemon serves.
## `[LOGGER]`
@@ -239,6 +243,16 @@ Read one row as **"on this OpenBridge, this TGID *is* this bridge."** That singl
`OBP_BRIDGES` is optional — omit it (or leave it `{}`) if you run no OpenBridges.
### Migrating from the old inline form
Earlier HBlink3 configured OpenBridge systems as inline `BRIDGES` members. To convert an existing `rules.py`, run the migration tool from the repo root:
```bash
python tools/migrate_obp_rules.py --config hblink.cfg --rules rules.py --out rules.py.migrated
```
It reads `hblink.cfg` to learn which systems are `OPENBRIDGE`, lifts each inline OBP member into `OBP_BRIDGES`, prints a summary of what moved, flags any ingress-fork **ERROR** or renumber **WARNING**, and writes a new file (it never overwrites your `rules.py`). Review the output — comments from the original are not carried over — then replace `rules.py` with it.
## `UNIT`
```python
+6 -5
View File
@@ -38,11 +38,11 @@ Edit `hblink.cfg`:
- **[LOGGER]** — log file, handlers, and level.
- **[ALIASES]** — optional download of repeater/subscriber ID files from radioid.net.
- **System stanzas** — one per connection. Set `MODE` to:
- `MASTER` — accept incoming repeaters/hotspots
- `PEER` — connect outward to another master
- `SERVER` — accept incoming repeaters/hotspots (formerly `MASTER`)
- `OUTBOUND` — connect outward to another server (formerly `PEER`/`CLIENT`)
- `OPENBRIDGE` — link to Brandmeister / DMR+ (IPSC2)
Duplicate a stanza for each system; the stanza name (e.g. `[MASTER-1]`) must be unique.
Duplicate a stanza for each system; the stanza name (e.g. `[SERVER-1]`) must be unique.
If you are running `bridge.py`, also create the rules file:
@@ -53,9 +53,10 @@ cp rules_SAMPLE.py rules.py
`rules.py` defines:
- **`BRIDGES`** — each conference bridge and the system / timeslot / talkgroup that belongs to it, with optional ON/OFF/RESET trigger talkgroups and timeouts.
- **`OBP_BRIDGES`** — OpenBridge (`OPENBRIDGE`) systems only: a per-OBP `{bridge: TGID}` table (not inline `BRIDGES` members). See [CONFIGURING.md](CONFIGURING.md#obp_bridges).
- **`UNIT`** — the systems permitted to exchange private (unit) calls.
Every system named in `rules.py` must exist and be enabled in `hblink.cfg`.
Every system named in `rules.py` must exist and be enabled in `hblink.cfg`. **Upgrading from an older HBlink3?** OpenBridge members used to live inline in `BRIDGES`; convert your file with `python tools/migrate_obp_rules.py` (see [CONFIGURING.md](CONFIGURING.md#obp_bridges)).
## 3. Run
@@ -65,7 +66,7 @@ python bridge.py -c hblink.cfg -r rules.py # conference-bridge router (main
# or
python bridge_all.py -c hblink.cfg # forward-everything proxy
# or
python hblink.py -c hblink.cfg # protocol core, standalone master/peer
python hblink.py -c hblink.cfg # protocol core, standalone server/outbound
```
`-c` / `-r` default to `hblink.cfg` and `rules.py` in the program directory. `-l LEVEL` overrides the configured log level.
+10 -4
View File
@@ -4,17 +4,23 @@ HBlink3 is an open-source implementation of the DMR **HomeBrew Repeater Protocol
> **Which HBlink?** HBlink3 is "system-oriented" and built for **transit routing and conference bridging** between networks. Its companion, **HBlink4** (by the same author), is a repeater-oriented **endpoint server** for running a single end-point network with no granudlar transit routing. Pick the one that matches your role.
> ⚠️ **Upgrading? Two breaking config changes to know about.**
> 1. **OpenBridge routing moved** — `MODE: OPENBRIDGE` systems are no longer inline `BRIDGES` members in `rules.py`; they now live in a dedicated **`OBP_BRIDGES`** table. Old configs stop with a clear startup error. Run **`python tools/migrate_obp_rules.py`** to convert your `rules.py` automatically, or see [CONFIGURING.md](CONFIGURING.md#obp_bridges).
> 2. **System modes renamed** — `MASTER`→**`SERVER`** and `PEER`/`CLIENT`→**`OUTBOUND`** (`OPENBRIDGE` unchanged). Update the `MODE:` line of each stanza in `hblink.cfg`.
>
> Your `hblink.cfg`/`rules.py` are git-ignored, so a `git pull` won't touch them — but the new code won't accept the old values. Non-OpenBridge configs need only change (2).
## Applications
| Program | Purpose |
|---|---|
| `bridge.py` | The main application: a configurable conference-bridge call router with dynamic on/off triggering, timeouts, and private (unit) call routing. |
| `bridge_all.py` | A simple proxy that forwards all traffic between every configured system — makes several repeaters appear as one. |
| `hblink.py` | The protocol core. Runs standalone as a master/peer for testing, and is the module the applications are built on. |
| `hblink.py` | The protocol core. Runs standalone as a server/outbound system for testing, and is the module the applications are built on. |
## Features
- HBP **server** (master) and **client** (peer) modes for MMDVM repeaters and hotspots
- HBP **server** and **outbound** (client) modes for MMDVM repeaters and hotspots
- **OpenBridge** connectivity to other transit call routers, including Brandmeister / DMR+ (IPSC2)
- Rules-based **conference-bridge routing** with dynamic ON/OFF/RESET talkgroup triggers and timeouts, including the ability to use TGIDs as in-band signalling to trigger dynamic connections -- sometimes referred to as "dial-a-talkgroup".
- **Private (unit) call** routing using a learned subscriber-to-system map that only floods systems configured for unit calls, and only until the target unit's system is located. It then prunes re-transmission to the system with the target unit.
@@ -38,7 +44,7 @@ See **[INSTALL.md](INSTALL.md)** for full setup, configuration, and running as a
## Configuration
- **`hblink.cfg`** — global settings, reporting, logging, alias downloads, and one stanza per system (`MASTER`, `PEER`, or `OPENBRIDGE`). Start from `hblink-SAMPLE.cfg`.
- **`hblink.cfg`** — global settings, reporting, logging, alias downloads, and one stanza per system (`SERVER`, `OUTBOUND`, or `OPENBRIDGE`). Start from `hblink-SAMPLE.cfg`.
- **`rules.py`** — (`bridge.py` only) defines the conference bridges, the systems/talkgroups/timeslots that belong to each, and the systems permitted to pass unit calls. Start from `rules_SAMPLE.py`.
Your `hblink.cfg` and `rules.py` are git-ignored, so `git pull` won't overwrite them.
@@ -79,7 +85,7 @@ used. Talkgroup IDs not present in the file are displayed as their raw numeric v
## Dashboard
A real-time web dashboard lives in [`dashboard/`](dashboard/) — a separate program
with a modern dark UI showing master/peer/OpenBridge systems, conference-bridge
with a modern dark UI showing server/outbound/OpenBridge systems, conference-bridge
state, and a live call log. Enable HBlink3's reporting feed (`[REPORTS]` in
`hblink.cfg`) and see [dashboard/README.md](dashboard/README.md) to run it. the dashboard
is kept separate to keep performance of the forwarding hot path free from unecessary
+7 -7
View File
@@ -39,16 +39,16 @@ and its state is remembered in your browser.
---
## Master Systems
## Server Systems
One block per HBlink3 **MASTER** instance (repeaters/hotspots connect *to* it).
One block per HBlink3 **SERVER** instance (repeaters/hotspots connect *to* it).
**Block heading**
| Element | Meaning |
|---|---|
| System name | The master's name from `hblink.cfg` (e.g. `MASTER-1`). |
| `repeat` / `isolate` pill | `repeat` if the master forwards traffic between its own peers (`REPEAT: True`), `isolate` if it does not. |
| System name | The server's name from `hblink.cfg` (e.g. `SERVER-1`). |
| `repeat` / `isolate` pill | `repeat` if the server forwards traffic between its own repeaters (`REPEAT: True`), `isolate` if it does not. |
| *N* peer(s) | How many repeaters/hotspots are currently logged in. |
| Show/Hide Connections | Collapses this system's connection table. When collapsed, system-level TS1/TS2 activity pills replace it so live calls stay visible. Default from `SERVER_REPEATERS`; per-system state is remembered in your browser. |
@@ -64,10 +64,10 @@ One block per HBlink3 **MASTER** instance (repeaters/hotspots connect *to* it).
---
## Peer Systems
## Outbound Systems
One row per HBlink3 **PEER** instance (HBlink3 connecting *out* to an upstream
master, e.g. another HBlink or a BrandMeister/IPSC2 server).
One row per HBlink3 **OUTBOUND** instance (HBlink3 connecting *out* to an upstream
server, e.g. another HBlink or a BrandMeister/IPSC2 server).
| Column | Meaning |
|---|---|
+12 -6
View File
@@ -14,13 +14,13 @@ full-table refreshes, and no pickle on the wire.
- **Last Heard** — the most-recent unique callers (user, call type, source
repeater, timeslot, talkgroup, and when), derived live from the call log. The
table is collapsible; its open/closed state is remembered in your browser.
- **Master Systems** — each master and its connected repeaters (ID, callsign,
- **Server Systems** — each server 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). Each server's
connection list can be collapsed with the **Show/Hide Connections** button;
when collapsed, system-level TS1/TS2 activity pills replace the table so you
still see what's talking. State is remembered per-browser.
- **Peer Systems** — outbound peer connections with health (connection state,
- **Outbound Systems** — outbound 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,
@@ -45,7 +45,11 @@ Open `http://<host>:8080`.
## Configuration (`config.py`)
- `HBLINK_IP` / `HBLINK_PORT` — HBlink3's reporting feed (the `[REPORTS]` section
of `hblink.cfg`: `REPORT_PORT`, default 4321).
of `hblink.cfg`: `REPORT_PORT`, default 4321). Used when `HBLINK_TRANSPORT` is `tcp`.
- `HBLINK_TRANSPORT` / `HBLINK_SOCKET` — optional. Set `HBLINK_TRANSPORT = 'unix'`
and `HBLINK_SOCKET` to the daemon's `REPORT_SOCKET` path to connect over a local
Unix socket instead of TCP (same-box dashboard; immune to NIC flaps / conntrack
eviction). Defaults to `tcp`. Must match the daemon's `REPORT_TRANSPORT`.
- `WEB_HOST` / `WEB_PORT` — where the dashboard listens.
- `PATH` / `*_FILE` — alias files mapping DMR IDs to callsigns/talkgroup names
(the same files HBlink3 uses; point `PATH` at HBlink3's directory to share them).
@@ -64,9 +68,11 @@ In `hblink.cfg`, under `[REPORTS]`:
- `REPORT: True`
- `REPORT_PORT` must match the dashboard's `HBLINK_PORT`
- `REPORT_CLIENTS` must include the dashboard host's IP (or `*`)
- `REPORT_INTERVAL` sets how often the systems/bridge snapshot is refreshed.
**Live calls are pushed instantly**; connection/peer-state changes appear on the
next snapshot, so `10` is a good value for dashboard use.
- `REPORT_INTERVAL` sets how often the full systems/bridge snapshot is resent as a
slow resync. **Live calls and repeater connect/disconnect are pushed as they
happen** (granular events); the periodic snapshot is just a safety-net resync and
also carries the per-repeater ping-quality figures, so a larger value like `60`
is fine.
## Notes