Copy `adn-server.example.yaml` to `adn-server.yaml` and edit with your settings. Production config is not committed.
Copy `adn-server.example.yaml` to `adn-server.yaml` and edit with your settings. Production config is not committed.
The example includes an **integrated hotspot proxy** (`PROXY`) and optional **MySQL self-service** (`SELF_SERVICE`). For self-service, install the optional extra: `pip install -e ".[selfservice]"`. See [Hotspot proxy (integrated)](docs/en/server/user-guide/hotspot-proxy.md). Disable standalone **`adn-proxy`** if you use the integrated proxy on the same host.
### Voice configuration
### Voice configuration
Voice features (announcements, TTS, recording) use a separate config file. Copy `adn-voice.example.yaml` to `adn-voice.yaml` and edit. If the file does not exist, voice features are disabled (no error). Changes are hot-reloaded every 15 seconds.
Voice features (announcements, TTS, recording) use a separate config file. Copy `adn-voice.example.yaml` to `adn-voice.yaml` and edit. If the file does not exist, voice features are disabled (no error). Changes are hot-reloaded every 15 seconds.
**Integrated (default):** **`adn-server.py`** runs UDP fan-in from **`PROXY.LISTEN_PORT`** into **`PROXY.TARGET_SYSTEM`**; **`SELF_SERVICE`** in **`adn-server.yaml`** drives **RPTO** from MySQL **`Clients`**. See [Hotspot proxy (integrated)](../server/user-guide/hotspot-proxy.md).
- Reads **`PROXY`** and **`SELF_SERVICE`** from **`adn-proxy.yaml`** by default (or from the same file as the monitor when **`ADN_CONFIG_PATH`** is used without **`ADN_PROXY_CONFIG_PATH`** — see [Hotspot proxy](hotspot-proxy.md#configuration-file)).
- For each hotspot client, allocates a UDP port in **`PORT`…`PORT+GENERATOR-1`** (YAML **`PORT`** + **`GENERATOR`**, matching **`adn-server`**) and forwards to **`MASTER`**.
**Standalone (legacy, adn-monitor repo):**
- When **self-service** updates **`Clients.options`** and sets **`modified=1`**, the proxy sends **RPTO** to the **master** on a timer (~10 s). The **peer server** then applies options to the hotspot path (see [Self-service](self-service.md)).
**Why it is not part of the peer server binary:** it shares deployment, **`SELF_SERVICE`** MySQL, and packaging with the monitor stack — see [Why it ships with the monitor](hotspot-proxy.md#why-it-ships-with-the-monitor-not-inside-the-peer-server).
- Reads **`PROXY`** and **`SELF_SERVICE`** from **`adn-proxy.yaml`** by default (or from a combined monitor YAML via **`ADN_CONFIG_PATH`** — see [Hotspot proxy](hotspot-proxy.md#configuration-file)).
- For each hotspot client, allocates a UDP port in **`PORT`…`PORT+GENERATOR-1`** and forwards to **`MASTER`**.
- When **self-service** updates **`Clients.options`** and sets **`modified=1`**, the proxy sends **RPTO** to the **master** on a timer (~10 s).
**Details:** [Hotspot proxy](hotspot-proxy.md) (config keys, peer server port range, startup).
**Details:** [Hotspot proxy](hotspot-proxy.md) (integrated vs standalone, config keys, startup).
This document describes **`adn-monitor.yaml`**, used by the **Python monitor** (`monitor/monitor.py`) and the **PHP backend** (`backend/public/index.php`). Default path is usually **`monitor/adn-monitor.yaml`** (override with **`ADN_CONFIG_PATH`**).
This document describes **`adn-monitor.yaml`**, used by the **Python monitor** (`monitor/monitor.py`) and the **PHP backend** (`backend/public/index.php`). Default path is usually **`monitor/adn-monitor.yaml`** (override with **`ADN_CONFIG_PATH`**).
The **hotspot proxy** loads a **separate** file by default —**`proxy/adn-proxy.yaml`** — see [Hotspot proxy](hotspot-proxy.md). **`SELF_SERVICE`** (MySQL / PBKDF2) must stay **identical**between the two YAML files when both are used.
**Integrated hotspot proxy:** **`PROXY`** and **`SELF_SERVICE`** in **`adn-server.yaml`** (see [Hotspot proxy (integrated)](../server/user-guide/hotspot-proxy.md)). **Standalone (legacy):****`proxy/adn-proxy.yaml`** — see [Hotspot proxy](hotspot-proxy.md). **`SELF_SERVICE`** (MySQL / PBKDF2) must stay **identical**across **`adn-server.yaml`**, **`adn-monitor.yaml`**, and legacy **`adn-proxy.yaml`** when used.
The example shipped in the **adn-monitor** repo (`monitor/adn-monitor.yaml.example`) is the template for the monitor; keys below match that file and `monitor/src/adn_monitor/infrastructure/config_loader.py` (internal names may differ).
The example shipped in the **adn-monitor** repo (`monitor/adn-monitor.yaml.example`) is the template for the monitor; keys below match that file and `monitor/src/adn_monitor/infrastructure/config_loader.py` (internal names may differ).
@ -50,9 +50,9 @@ If the PHP backend cannot connect, **auth** and **self-service** API routes are
## `PROXY`
## `PROXY`
Hotspot **UDP proxy** — full guide: [Hotspot proxy](hotspot-proxy.md). In current layouts, these keys live in **`proxy/adn-proxy.yaml`**, not in `adn-monitor.yaml`. **Legacy:** a single file can still contain **PROXY** if the proxy is started with **`ADN_CONFIG_PATH`** pointing at that file (see resolution order in [Hotspot proxy](hotspot-proxy.md#configuration-file)).
Hotspot **UDP proxy** — full guide: [Hotspot proxy](hotspot-proxy.md). **Integrated** deployments use **`PROXY`** in **`adn-server.yaml`** (fan-in, no port range). **Standalone** layouts keep these keys in **`proxy/adn-proxy.yaml`** (or a legacy combined file via **`ADN_CONFIG_PATH`**).
Summary: **`PORT`** + **`GENERATOR`** must match **`SYSTEM.PORT`** + **`SYSTEM.GENERATOR`** in `adn-server`; each client is forwarded to **`MASTER`** at one UDP port in **`PORT`…`PORT+GENERATOR-1`** (see also [Architecture](architecture.md)).
**Standalone summary:****`PORT`** + **`GENERATOR`** must match **`SYSTEM.PORT`** + **`SYSTEM.GENERATOR`** in `adn-server`; each client is forwarded to **`MASTER`** at one UDP port in **`PORT`…`PORT+GENERATOR-1`** (see also [Architecture](architecture.md)).
The **hotspot proxy** is part of the **adn-monitor** repository. It is a **UDP relay** between **DMR hotspots** (Homebrew / HBP) and the **ADN DMR Peer Server** MASTER: each connected hotspot is mapped to a **dedicated destination port** on the peer server host so many hotspots can share one public IP without port clashes.
## Integrated proxy (current default)
Source layout: `proxy/proxy.py`, package `proxy/src/adn_proxy/` (clean architecture). **GPL v3** (derivative of Simon Adlem, G7RZU’s original proxy).
**ADN DMR Peer Server** ships an **integrated hotspot proxy** in **`adn-server.py`**. Configure **`PROXY`** and **`SELF_SERVICE`** in **`adn-server.yaml`** — see [Hotspot proxy (integrated)](../server/user-guide/hotspot-proxy.md).
- Hotspots connect to **`PROXY.LISTEN_PORT`** only (fan-in).
- Traffic injects into **`PROXY.TARGET_SYSTEM`** (inject-only MASTER, **`MAX_PEERS`**).
- MySQL self-service uses the same **`Clients`** table as this monitor stack.
- **Disable** standalone **`adn-proxy`** on the same host to avoid **`LISTEN_PORT`** conflicts.
---
## Standalone proxy (legacy, adn-monitor repo)
### Why it ships with the monitor (not inside the peer server)
The **adn-monitor** repository still contains a **standalone UDP relay** (`proxy/proxy.py`). It maps each hotspot to a **dedicated destination port** on the peer server host (port **range** + **`GENERATOR`**). Use this layout only when you deliberately keep proxy separate from **`adn-server`**.
There is no single mandatory layout for every deployment, but **today the proxy lives in the adn-monitor repo** on purpose:
Source layout: `proxy/proxy.py`, package `proxy/src/adn_proxy/` (clean architecture). **GPL v3** (derivative of Simon Adlem, G7RZU’s original proxy).
- **Same deployment** as the dashboard stack: **`ADN_CONFIG_PATH`** / **`ADN_PROXY_CONFIG_PATH`**, **`adn-monitor.yaml`** + **`adn-proxy.yaml`**, and usually the same host as **PHP** and **MySQL**.
### Why it also ships with the monitor
- **Self-service** ( **`Clients`**, RPTO, **`modified`**) is built around that ecosystem; the peer server binary does not own that database or the **`PROXY`** block.
- **Role split:** the **ADN DMR Peer Server** is the **radio core** (HBP/OpenBridge, bridges, voice, TCP reports). The hotspot proxy is an **optional UDP front** toward a MASTER that already listens on a port **range** — useful when many hotspots share one public address.
**Bundling the proxy into the peer server** (one binary, one `adn-server.yaml`) is conceivable for packaging, but it implies **merging configuration**, **rethinking self-service wiring**, and extra maintenance — only worth it if you explicitly want a single deployable “all-in-one” server.
- **Same deployment** as the dashboard stack: **`adn-monitor.yaml`**, **`adn-proxy.yaml`**, **PHP**, **MySQL**.
- Historical split: peer server = radio core; proxy = optional UDP front on a port **range**.
- New ADN deployments should prefer the **integrated** proxy unless you maintain an existing **`adn-proxy`** unit.
---
---
## Configuration file {#configuration-file}
## Configuration file {#configuration-file}
The proxy does **not** use `adn-server.yaml`. It reads YAML that contains **`PROXY`**, **`SELF_SERVICE`**, and **`LOGGER`** (proxy log).
The **standalone**proxy does **not** use `adn-server.yaml` for its own process. It reads YAML that contains **`PROXY`**, **`SELF_SERVICE`**, and **`LOGGER`** (proxy log). The **integrated** proxy reads those blocks from **`adn-server.yaml`** instead.
**ADN Monitor** is a separate project from the **ADN DMR Peer Server**, but the two are normally deployed **together**: the server sends **TCP reports** (config, bridges, call events) to the monitor; the monitor drives the **web dashboard** (React) and **WebSocket** live updates. Optional components include the **PHP API** (Slim), **MySQL** (self-service / device registry), and the **hotspot proxy** (UDP between hotspots and the peer server).
**ADN Monitor** is a separate project from the **ADN DMR Peer Server**, but the two are normally deployed **together**: the server sends **TCP reports** (config, bridges, call events) to the monitor; the monitor drives the **web dashboard** (React) and **WebSocket** live updates. Optional components include the **PHP API** (Slim), **MySQL** (self-service / device registry), and the **hotspot proxy** (UDP between hotspots and the peer server — **integrated in `adn-server.py`** by default; standalone `adn-proxy` remains for legacy layouts).
This chapter documents the **adn-monitor** stack at the same level of detail as the server guides. Source code lives in the **adn-monitor** repository, not in the **adn-server** repository (where this documentation is maintained).
This chapter documents the **adn-monitor** stack at the same level of detail as the server guides. Source code lives in the **adn-monitor** repository, not in the **adn-server** repository (where this documentation is maintained).
@ -11,16 +11,17 @@ This chapter documents the **adn-monitor** stack at the same level of detail as
| **`monitor/monitor.py`** | Python (Twisted): connects to the peer server’s **report TCP** port, decodes netstring payloads (`CONFIG_SND`, `BRIDGE_SND`, `BRDG_EVENT`), maintains **CTABLE** / **BTABLE**, writes **Last Heard** / TG stats to **MySQL** when configured, serves **WebSocket** JSON to the dashboard. |
| **`monitor/monitor.py`** | Python (Twisted): connects to the peer server’s **report TCP** port, decodes netstring payloads (`CONFIG_SND`, `BRIDGE_SND`, `BRDG_EVENT`), maintains **CTABLE** / **BTABLE**, writes **Last Heard** / TG stats to **MySQL** when configured, serves **WebSocket** JSON to the dashboard. |
| **`backend/`** | PHP **Slim** app: `/api/config/dashboard`, auth, optional **self-service** APIs, alias proxies. Reads **`adn-monitor.yaml`** via **`ADN_CONFIG_PATH`**. |
| **`backend/`** | PHP **Slim** app: `/api/config/dashboard`, auth, optional **self-service** APIs, alias proxies. Reads **`adn-monitor.yaml`** via **`ADN_CONFIG_PATH`**. |
| **`proxy/`** | Python (Twisted): UDP **hotspot proxy**; forwards Homebrew between hotspots and the peer server; reads **`Clients`** in MySQL for **RPTO** options (self-service). Loads **`adn-proxy.yaml`** by default (see [Hotspot proxy](hotspot-proxy.md)). |
| **`proxy/`** | Python (Twisted): **standalone** UDP hotspot proxy (legacy); forwards Homebrew between hotspots and the peer server port range; reads **`Clients`** in MySQL for **RPTO**. Prefer integrated **`PROXY`** in **`adn-server.yaml`** — see [Hotspot proxy](hotspot-proxy.md). |
## Configuration files
## Configuration files
| File | Used by | Typical env |
| File | Used by | Typical env |
|------|---------|-------------|
|------|---------|-------------|
| **`adn-server.yaml`** | **`adn-server.py`** (integrated **`PROXY`** / **`SELF_SERVICE`**) | `-c` / default path next to binary |
**`SELF_SERVICE`** (MySQL / PBKDF2) must **match** between both YAML files when you split config. **`ADN_CONNECTION`**, dashboard, WebSocket, and aliases live in **`adn-monitor.yaml`**; **`PROXY`** listen/master/range settings live in **`adn-proxy.yaml`** unless you use a **legacy** single file via **`ADN_CONFIG_PATH`** for the proxy.
**`SELF_SERVICE`** (MySQL / PBKDF2) must **match** between **`adn-server.yaml`** (integrated proxy), **`adn-monitor.yaml`**, and legacy **`adn-proxy.yaml`** when used. **`ADN_CONNECTION`**, dashboard, WebSocket, and aliases live in **`adn-monitor.yaml`**; integrated **`PROXY`** / **`SELF_SERVICE`** live in **`adn-server.yaml`**; standalone proxy settings remain in **`adn-proxy.yaml`**.
@ -33,9 +33,9 @@ With **systemd**, add to your unit file:
ExecReload=/bin/kill -HUP $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
```
```
**Reload applies:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (without process restart), per-system settings, **new/removed SYSTEMS** (including `GENERATOR` expansion and new OpenBridge legs), and updated bind addresses (listener restart for that system only).
**Reload applies:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (without process restart), **`PROXY`** (timeouts, debug, block lists — not bind or target), **`SELF_SERVICE`** (merged; enabling/disabling DB loops needs restart), per-system settings, **new/removed SYSTEMS** (including `GENERATOR` expansion/collapse and new OpenBridge legs), and updated bind addresses (listener restart for that system only).
**Not reloaded:** `adn-voice.yaml` (separate 15 s loop), Python code, subscriber alias files (separate periodic reload). **BRIDGES** table is not rebuilt on reload — restart if bridge rules changed in a way that requires a full reset.
**Not reloaded:** `adn-voice.yaml` (separate 15 s loop), Python code, subscriber alias files (separate periodic reload). **BRIDGES** table is not rebuilt on reload — restart if bridge rules changed in a way that requires a full reset.**`PROXY.LISTEN_PORT`**, **`LISTEN_IP`**, and **`TARGET_SYSTEM`** require a **full restart** to take effect.
**Secrets:** Never commit real passphrases, security URLs, or `user_passwords.json` / `encryption_key.secret`. Use placeholders in templates and keep production files local.
**Secrets:** Never commit real passphrases, security URLs, or `user_passwords.json` / `encryption_key.secret`. Use placeholders in templates and keep production files local.
@ -115,16 +115,16 @@ These appear mainly on **MASTER** (and often on **PEER**). OpenBridge uses a dif
| Key | Meaning |
| Key | Meaning |
|-----|---------|
|-----|---------|
| **REPEAT** | If true, received traffic can be **repeated** to other connected peers on the MASTER (typical conference behaviour). |
| **REPEAT** | If true, received traffic can be **repeated** to other connected peers on the MASTER (typical conference behaviour). |
| **MAX_PEERS** | Maximum connected hotspots. |
| **MAX_PEERS** | Maximum connected hotspots. On the **proxy target** MASTER, caps concurrent fan-in sessions. |
| **EXPORT_AMBE** | Feature flag for AMBE export (if enabled in build). |
| **EXPORT_AMBE** | Feature flag for AMBE export (if enabled in build). |
| **VOICE_IDENT** | Enables periodic **voice ident** when conditions are met (see `IdentUseCases`). |
| **VOICE_IDENT** | Enables periodic **voice ident** when conditions are met (see `IdentUseCases`). |
| **TS1_STATIC** / **TS2_STATIC** | Comma-separated static TG lists pushed via OPTIONS handling (see `options_config`). |
| **TS1_STATIC** / **TS2_STATIC** | Comma-separated static TG lists pushed via OPTIONS handling (see `options_config`). |
| **DEFAULT_REFLECTOR** | Default **reflector** number for `#` dial bridges (0 = none). |
| **DEFAULT_REFLECTOR** | Default **reflector** number for `#` dial bridges (0 = none). |
| **OVERRIDE_IDENT_TG** | Optional TG for voice ident instead of all-call. |
| **OVERRIDE_IDENT_TG** | Optional TG for voice ident instead of all-call. |
| **GENERATOR** | If **> 1**, this MASTER is expanded into **`NAME-0`**, **`NAME-1`**, … with consecutive ports (see `expand_generator` in code). |
| **GENERATOR** | If **> 1**, this MASTER is expanded into **`NAME-0`**, **`NAME-1`**, … with consecutive ports (see `expand_generator` in code). Legacy standalone **`adn-proxy`** used the same range; the **integrated** proxy instead uses **inject-only****`PROXY.TARGET_SYSTEM`** (no per-hotspot UDP ports on the server). |
**MASTER** listens for PEER connections; each authenticated peer is stored under **`PEERS`** at runtime.
**MASTER** listens for PEER connections (unless it is the **inject-only** proxy target — see [Hotspot proxy](hotspot-proxy.md)); each authenticated peer is stored under **`PEERS`** at runtime.
---
---
@ -186,6 +186,28 @@ Details: [Monitoring and reports](monitoring.md).
---
---
## `PROXY` (integrated hotspot proxy)
Always started when a **`PROXY`** block is present (see `adn-server.example.yaml`). Hotspots connect to **`LISTEN_PORT`**; traffic is injected into **`TARGET_SYSTEM`**. Full guide: [Hotspot proxy](hotspot-proxy.md).
| **BLACK_LIST** / **IP_BLACK_LIST** | Block radio IDs or client IPs. |
Do **not** run standalone **`adn-proxy`** on the same **`LISTEN_PORT`** when the integrated proxy is enabled.
---
## `SELF_SERVICE` (MySQL / dashboard options)
Optional; requires `pip install -e ".[selfservice]"` when **`USE_SELFSERVICE: true`**. Uses the same **`Clients`** table and PBKDF2 parameters as **adn-monitor**. Keys match the monitor docs — see [Self-service](../../monitor/self-service.md) and [Hotspot proxy](hotspot-proxy.md#self_service-keys).
---
## `LOGGER`
## `LOGGER`
Implemented in `infrastructure/logging_config.py` (`setup_logging`). Values are read from the **`LOGGER`** block (or overridden by `--logging` for **LOG_LEVEL** only).
Implemented in `infrastructure/logging_config.py` (`setup_logging`). Values are read from the **`LOGGER`** block (or overridden by `--logging` for **LOG_LEVEL** only).
@ -247,3 +269,4 @@ Use the project interpreter (see workspace rules), e.g. `python3.11` from pyenv,
- [Bridges and talkgroups](bridges-and-talkgroups.md) — `BRIDGES` semantics.
- [Bridges and talkgroups](bridges-and-talkgroups.md) — `BRIDGES` semantics.
- [Special numbers](special-numbers.md) — reserved TGs and server IDs.
- [Special numbers](special-numbers.md) — reserved TGs and server IDs.
- [Parrot](parrot.md) — PEER example (parrot process).
- [Parrot](parrot.md) — PEER example (parrot process).
**ADN DMR Peer Server** includes an **integrated hotspot proxy**: one process (`adn-server.py`) accepts Homebrew (HBP) from many hotspots on a single UDP port and **injects** traffic into a configured **MASTER** system. You do **not** need a separate **`adn-proxy`** process when this mode is enabled.
Configuration lives in **`adn-server.yaml`** under **`PROXY`** and optional **`SELF_SERVICE`** (same MySQL **`Clients`** table as **adn-monitor**).
---
## When to use it
| Deployment | What to run |
|------------|-------------|
| **Typical ADN stack** (monitor + dashboard + many Pi-Star hotspots) | **`adn-server.py`** with **`PROXY`** + **`SELF_SERVICE`** — disable the standalone **`adn-proxy`** unit to avoid port clashes on **`PROXY.LISTEN_PORT`**. |
| **Legacy / split config** | Standalone **`proxy/proxy.py`** in the **adn-monitor** repo — see [Hotspot proxy (standalone)](../../monitor/hotspot-proxy.md). |
The integrated proxy uses **fan-in**: hotspots only need **`PROXY.LISTEN_PORT`** (e.g. **62031**). The target **MASTER** is **inject-only** — it does **not** bind its own UDP port for that system (no per-hotspot port range on the server host).
---
## Optional dependency (self-service)
MySQL self-service requires **`mysqlclient`**:
```bash
pip install -e ".[selfservice]"
```
If **`USE_SELFSERVICE: true`** but **`mysqlclient`** is missing, startup fails with a clear error. Set **`USE_SELFSERVICE: false`** to run the proxy without DB (no dashboard-driven **RPTO** updates).
---
## `PROXY` keys
| Key | Role |
|-----|------|
| **LISTEN_PORT** | UDP port where **hotspots** connect (the address users configure on the hotspot). |
| **LISTEN_IP** | Bind address; empty = all interfaces. |
| **TARGET_SYSTEM** | Name of the **`SYSTEMS`** **MASTER** entry that receives injected HBP (must exist and be **ENABLED**). |
| **TIMEOUT** | Idle session timeout (seconds); expired sessions are torn down on the MASTER. |
| **DEBUG** | Verbose packet logging. |
| **CLIENT_INFO** | Log connect/disconnect per radio ID. |
There is **no****`MASTER`**, **`PORT`**, or **`GENERATOR`** in integrated **`PROXY`** — those belong to the legacy standalone proxy. The target MASTER uses **`MAX_PEERS`** (not a UDP port range) to cap concurrent hotspot sessions.
Example (from `adn-server.example.yaml`):
```yaml
PROXY:
LISTEN_PORT: 62031
LISTEN_IP: ""
TARGET_SYSTEM: SYSTEM
TIMEOUT: 30
DEBUG: false
CLIENT_INFO: true
BLACK_LIST: []
IP_BLACK_LIST: {}
```
### Inject-only target MASTER
When **`PROXY.TARGET_SYSTEM`** points at a system (e.g. **`SYSTEM`**), startup **removes****`IP`** / **`PORT`** from that MASTER block. Hotspots never connect directly to the conference port; all HBP enters via **`LISTEN_PORT`**.
Set **`MAX_PEERS`** on the target MASTER to the maximum concurrent proxied hotspots (e.g. **102**). Other MASTER systems (e.g. **ECHO**, **D-APRS**) keep normal **`IP`** / **`PORT`** binds if they are not the proxy target.
---
## `SELF_SERVICE` keys
Same semantics as **`adn-monitor.yaml`** / legacy **`adn-proxy.yaml`** — shared **`Clients`** table, **`modified`** flag, **RPTO** toward the MASTER.
| **DB_SERVER**, **DB_USERNAME**, **DB_PASSWORD**, **DB_NAME**, **DB_PORT** | MySQL connection. |
| **PBKDF2_SALT**, **PBKDF2_ITERATIONS** | Must **match** monitor/backend for password hashing. |
On startup the server logs **`(SELF_SERVICE) Database connection test: OK`** and **`(SELF_SERVICE) Enabled`** when the pool connects. Self-service runs **asynchronously**; voice forwarding is not blocked on DB latency.
Details of the dashboard flow: [Self-service](../../monitor/self-service.md).
---
## Multi-hotspot behaviour
- Each authenticated hotspot is a **peer** on the inject-only MASTER with its own **OPTIONS** (static TGs). **Repeat** and monitor fan-out respect **per-peer OPTIONS** — traffic for a TG is not sent to peers that did not select it.
- **Parrot / echo** talkgroups **9990–9999** bypass the OPTIONS filter and return to the **calling** hotspot (see [Special numbers](special-numbers.md)).
---
## Hot reload (`SIGHUP`)
**Applied without restart** (active proxy sessions stay up):
- **`SELF_SERVICE`:** merged into config (credential changes take effect on new DB operations; loops are not restarted on reload)
**Requires full process restart:**
- **`PROXY.LISTEN_PORT`** / **`LISTEN_IP`** (bind change is logged and ignored at reload)
- **`PROXY.TARGET_SYSTEM`**
- Enabling or disabling **`USE_SELFSERVICE`** after startup (start/stop MySQL loops)
See [Configuration — hot reload](configuration.md#hot-reload-adn-serveryaml).
---
## Standalone proxy (legacy)
The **adn-monitor** repository still ships **`proxy/proxy.py`** for deployments that keep a **separate** UDP relay and **`adn-proxy.yaml`**. Do **not** run both the integrated proxy and standalone **`adn-proxy`** on the same **`LISTEN_PORT`**.
---
## See also
- [Configuration](configuration.md) — full **`adn-server.yaml`** reference.
- [Monitoring and reports](monitoring.md) — TCP reports, dashboard, log rotation.
| **Hotspot proxy** | Optional integrated UDP fan-in (`PROXY` in `adn-server.yaml`) plus MySQL **self-service** (`SELF_SERVICE`) for dashboard-driven hotspot options. |
## Related programs
## Related programs
- **Parrot / playback** — separate entrypoint (`adn-parrot.py`) for record-and-playback; see [Parrot](parrot.md).
- **Parrot / playback** — separate entrypoint (`adn-parrot.py`) for record-and-playback; see [Parrot](parrot.md).
- **Standalone hotspot proxy** — legacy `adn-proxy` in the **adn-monitor** repo when not using the integrated proxy; see [Hotspot proxy (standalone)](../../monitor/hotspot-proxy.md).
@ -50,8 +50,8 @@ These processes handle **`SIGUSR2`** by reopening **`logging.FileHandler`** stre
| Process | Typical config keys |
| Process | Typical config keys |
|---------|---------------------|
|---------|---------------------|
| **`adn-server`** / **`adn-parrot`** | **`LOGGER.LOG_FILE`** (see `adn-server.example.yaml`) |
| **`adn-server`** / **`adn-parrot`** | **`LOGGER.LOG_FILE`** (integrated proxy logs appear in the same file) |
| **`adn-proxy`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** in `adn-proxy.yaml` |
| **`adn-proxy`** (standalone, legacy) | **`LOG.PATH`** + **`LOG.LOG_FILE`** in `adn-proxy.yaml` — omit if using integrated **`PROXY`** in `adn-server.yaml` |
| **`adn-monitor`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** in `adn-monitor.yaml` |
| **`adn-monitor`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** in `adn-monitor.yaml` |
Example **`/etc/logrotate.d/adn`** fragment (adjust paths and service names):
Example **`/etc/logrotate.d/adn`** fragment (adjust paths and service names):
@ -71,7 +71,7 @@ Example **`/etc/logrotate.d/adn`** fragment (adjust paths and service names):
}
}
```
```
Repeat **`postrotate`** with **`kill -USR2`** for **`adn-parrot`**, **`adn-proxy`**, and **`adn-monitor`** units if those logs are rotated on the same host. Use the correct **PID** (systemd **`MainPID`**, a pidfile, or **`kill`** targeting the process you manage).
Repeat **`postrotate`** with **`kill -USR2`** for **`adn-parrot`** and **`adn-monitor`** units if those logs are rotated on the same host. Add **`adn-proxy`** only when you still run the **standalone** proxy (not needed when proxy is integrated into **`adn-server`**). Use the correct **PID** (systemd **`MainPID`**, a pidfile, or **`kill`** targeting the process you manage).
## Requirements
## Requirements
@ -80,4 +80,6 @@ Repeat **`postrotate`** with **`kill -USR2`** for **`adn-parrot`**, **`adn-proxy
## Self-service and hotspots
## Self-service and hotspots
Operators editing **device options** from the dashboard use the **self-service** flow (MySQL **`Clients`**, proxy **RPTO**). That is documented under [Self-service](../../monitor/self-service.md); it is **not** part of the peer server binary alone. For **hotspot proxy** configuration (`PROXY` in **`adn-proxy.yaml`** by default), how it binds to the peer server **UDP port range**, and how the process starts, see [Hotspot proxy](../../monitor/hotspot-proxy.md).
Operators editing **device options** from the dashboard use the **self-service** flow (MySQL **`Clients`**, **RPTO** toward the conference MASTER). In current **ADN DMR Peer Server** deployments this runs **inside `adn-server.py`**: configure **`SELF_SERVICE`** and **`PROXY`** in **`adn-server.yaml`** (see [Hotspot proxy](hotspot-proxy.md)). Dashboard semantics: [Self-service](../../monitor/self-service.md).
Legacy stacks may still use a **standalone****`adn-proxy`** process and **`adn-proxy.yaml`** — see [Hotspot proxy (standalone)](../../monitor/hotspot-proxy.md). Do not run both on the same **`LISTEN_PORT`**.
**Integrado (predeterminado):** **`adn-server.py`** ejecuta fan-in UDP desde **`PROXY.LISTEN_PORT`** hacia **`PROXY.TARGET_SYSTEM`**; **`SELF_SERVICE`** en **`adn-server.yaml`** impulsa **RPTO** desde MySQL **`Clients`**. Ver [Proxy hotspot (integrado)](../server/user-guide/hotspot-proxy.md).
- Lee **`PROXY`** y **`SELF_SERVICE`** desde **`adn-proxy.yaml`** por defecto (o desde el mismo fichero que el monitor si se usa solo **`ADN_CONFIG_PATH`** sin **`ADN_PROXY_CONFIG_PATH`** — ver [Proxy hotspot](hotspot-proxy.md#configuration-file)).
- Por cada cliente hotspot, asigna un puerto UDP en **`PORT`…`PORT+GENERATOR-1`** (**`PORT`** + **`GENERATOR`** en YAML, alineados con **`adn-server`**) y reenvía a **`MASTER`**.
**Independiente (legado, repo adn-monitor):**
- Cuando **self-service** actualiza **`Clients.options`** y pone **`modified=1`**, el proxy envía **RPTO** al **master** en un temporizador (~10 s). El **peer server** aplica entonces las opciones al camino del hotspot (ver [Self-service](self-service.md)).
**Por qué no forma parte del binario del peer server:** comparte implantación, **self-service** MySQL y empaquetado con la pila del monitor — ver [Por qué va con el monitor](hotspot-proxy.md#why-it-ships-with-the-monitor-not-inside-the-peer-server).
- Lee **`PROXY`** y **`SELF_SERVICE`** desde **`adn-proxy.yaml`** por defecto (o YAML combinado del monitor vía **`ADN_CONFIG_PATH`** — ver [Proxy hotspot](hotspot-proxy.md#configuration-file)).
- Por cada cliente hotspot, asigna un puerto UDP en **`PORT`…`PORT+GENERATOR-1`** y reenvía a **`MASTER`**.
- Cuando **self-service** actualiza **`Clients.options`** y pone **`modified=1`**, el proxy envía **RPTO** al **master** en un temporizador (~10 s).
**Detalle:** [Proxy hotspot](hotspot-proxy.md) (claves de config, rango de puertos del peer, arranque).
**Detalle:** [Proxy hotspot](hotspot-proxy.md) (integrado vs independiente, claves, arranque).
Este documento describe **`adn-monitor.yaml`**, usado por el **monitor Python** (`monitor/monitor.py`) y el **backend PHP** (`backend/public/index.php`). La ruta por defecto suele ser **`monitor/adn-monitor.yaml`** (sobrescribible con **`ADN_CONFIG_PATH`**).
Este documento describe **`adn-monitor.yaml`**, usado por el **monitor Python** (`monitor/monitor.py`) y el **backend PHP** (`backend/public/index.php`). La ruta por defecto suele ser **`monitor/adn-monitor.yaml`** (sobrescribible con **`ADN_CONFIG_PATH`**).
El **proxy hotspot** carga por defecto **otro** fichero —**`proxy/adn-proxy.yaml`** — ver [Proxy hotspot](hotspot-proxy.md). La sección **`SELF_SERVICE`** (MySQL / PBKDF2) debe ser **idéntica** en ambos YAML cuando se usan los dos.
**Proxy hotspot integrado:** **`PROXY`** y **`SELF_SERVICE`** en **`adn-server.yaml`** (ver [Proxy hotspot (integrado)](../server/user-guide/hotspot-proxy.md)). **Independiente (legado):****`proxy/adn-proxy.yaml`** — ver [Proxy hotspot](hotspot-proxy.md). **`SELF_SERVICE`** (MySQL / PBKDF2) debe ser **idéntica** entre **`adn-server.yaml`**, **`adn-monitor.yaml`** y **`adn-proxy.yaml`** legado si se usa.
El ejemplo del repositorio **adn-monitor** (`monitor/adn-monitor.yaml.example`) es la plantilla del monitor; las claves siguientes coinciden con ese fichero y `monitor/src/adn_monitor/infrastructure/config_loader.py` (los nombres internos pueden diferir).
El ejemplo del repositorio **adn-monitor** (`monitor/adn-monitor.yaml.example`) es la plantilla del monitor; las claves siguientes coinciden con ese fichero y `monitor/src/adn_monitor/infrastructure/config_loader.py` (los nombres internos pueden diferir).
@ -50,9 +50,9 @@ Si el backend PHP no puede conectar, las rutas de **auth** y **self-service** no
## `PROXY`
## `PROXY`
**Proxy UDP hotspot** — guía completa: [Proxy hotspot](hotspot-proxy.md). En los despliegues actuales, estas claves están en **`proxy/adn-proxy.yaml`**, no en `adn-monitor.yaml`. **Legado:** un único fichero puede seguir incluyendo **PROXY** si el proxy se arranca con **`ADN_CONFIG_PATH`** apuntando a ese fichero (ver orden de resolución en [Proxy hotspot](hotspot-proxy.md#configuration-file)).
**Proxy UDP hotspot** — guía completa: [Proxy hotspot](hotspot-proxy.md). Los despliegues **integrados** usan **`PROXY`** en **`adn-server.yaml`** (fan-in, sin rango de puertos). Los layouts **independientes** mantienen estas claves en **`proxy/adn-proxy.yaml`** (o fichero combinado legado vía **`ADN_CONFIG_PATH`**).
Resumen: **`PORT`** + **`GENERATOR`** deben coincidir con **`SYSTEM.PORT`** + **`SYSTEM.GENERATOR`** en `adn-server`; cada cliente se reenvía a **`MASTER`** en un puerto UDP dentro de **`PORT`…`PORT+GENERATOR-1`** (ver también [Arquitectura](architecture.md)).
**Resumen independiente:****`PORT`** + **`GENERATOR`** deben coincidir con **`SYSTEM.PORT`** + **`SYSTEM.GENERATOR`** en `adn-server`; cada cliente se reenvía a **`MASTER`** en un puerto UDP dentro de **`PORT`…`PORT+GENERATOR-1`** (ver también [Arquitectura](architecture.md)).
El **proxy hotspot** forma parte del repositorio **adn-monitor**. Es un **relé UDP** entre **hotspots DMR** (Homebrew / HBP) y el **MASTER** del **ADN DMR Peer Server**: cada hotspot conectado se asigna a un **puerto de destino** dedicado en el host del peer server, de modo que muchos hotspots puedan compartir una IP pública sin choques de puertos.
## Proxy integrado (predeterminado actual)
Estructura: `proxy/proxy.py`, paquete `proxy/src/adn_proxy/` (arquitectura limpia). **GPL v3** (derivado del proxy original de Simon Adlem, G7RZU).
**ADN DMR Peer Server** incluye un **proxy hotspot integrado** en **`adn-server.py`**. Configura **`PROXY`** y **`SELF_SERVICE`** en **`adn-server.yaml`** — ver [Proxy hotspot (integrado)](../server/user-guide/hotspot-proxy.md).
- Los hotspots se conectan solo a **`PROXY.LISTEN_PORT`** (fan-in).
- El tráfico se inyecta en **`PROXY.TARGET_SYSTEM`** (MASTER solo inyección, **`MAX_PEERS`**).
- El self-service MySQL usa la misma tabla **`Clients`** que este stack del monitor.
- **Desactiva****`adn-proxy`** independiente en el mismo host para evitar conflictos en **`LISTEN_PORT`**.
---
## Proxy independiente (legado, repo adn-monitor)
### Por qué va con el monitor (y no dentro del peer server) {#why-it-ships-with-the-monitor-not-inside-the-peer-server}
El repositorio **adn-monitor** sigue teniendo un **relé UDP independiente** (`proxy/proxy.py`). Asigna a cada hotspot un **puerto de destino dedicado** en el host del peer server (rango de puertos + **`GENERATOR`**). Usa este layout solo si mantienes el proxy separado de **`adn-server`** a propósito.
No hay un despliegue obligatorio único, pero **hoy el proxy vive en el repo adn-monitor** a propósito:
Estructura: `proxy/proxy.py`, paquete `proxy/src/adn_proxy/` (arquitectura limpia). **GPL v3** (derivado del proxy original de Simon Adlem, G7RZU).
- **Mismo despliegue** que el panel: **`ADN_CONFIG_PATH`** / **`ADN_PROXY_CONFIG_PATH`**, **`adn-monitor.yaml`** + **`adn-proxy.yaml`**, y normalmente el mismo host que **PHP** y **MySQL**.
### Por qué también va con el monitor {#why-it-ships-with-the-monitor-not-inside-the-peer-server}
- El **self-service** (**`Clients`**, RPTO, **`modified`**) está montado sobre ese ecosistema; el binario del peer server no posee esa base de datos ni el bloque **`PROXY`**.
- **División de roles:** el **ADN DMR Peer Server** es el **núcleo de radio** (HBP/OpenBridge, bridges, voz, informes TCP). El proxy hotspot es un **frente UDP opcional** hacia un MASTER que ya escucha en un **rango** de puertos — útil cuando muchos hotspots comparten una dirección pública.
**Integrar el proxy en el peer server** (un binario, un `adn-server.yaml`) es imaginable para empaquetado, pero implica **unificar configuración**, **replantear el cableado de self-service** y más mantenimiento — solo compensa si quieres explícitamente un servidor “todo en uno” desplegable.
- **Mismo despliegue** que el panel: **`adn-monitor.yaml`**, **`adn-proxy.yaml`**, **PHP**, **MySQL**.
- Separación histórica: peer server = núcleo radio; proxy = frontal UDP opcional en un **rango** de puertos.
- Los despliegues ADN nuevos deben preferir el proxy **integrado** salvo que mantengas una unidad **`adn-proxy`** existente.
---
---
## Fichero de configuración {#configuration-file}
## Fichero de configuración {#configuration-file}
El proxy **no** usa `adn-server.yaml`. Lee un YAML que incluye **`PROXY`**, **`SELF_SERVICE`** y **`LOGGER`** (log del proxy).
El proxy **independiente** **no** usa `adn-server.yaml` para su propio proceso. Lee un YAML que incluye **`PROXY`**, **`SELF_SERVICE`** y **`LOGGER`** (log del proxy). El proxy **integrado** lee esos bloques desde **`adn-server.yaml`**.
**ADN Monitor** es un proyecto distinto del **ADN DMR Peer Server**, pero ambos suelen desplegarse **juntos**: el servidor envía **informes TCP** (config, bridges, eventos de llamada) al monitor; el monitor alimenta el **panel web** (React) y las actualizaciones **WebSocket**. Los componentes opcionales incluyen la **API PHP** (Slim), **MySQL** (self-service / registro de dispositivos) y el **proxy hotspot** (UDP entre hotspots y el peer server).
**ADN Monitor** es un proyecto distinto del **ADN DMR Peer Server**, pero ambos suelen desplegarse **juntos**: el servidor envía **informes TCP** (config, bridges, eventos de llamada) al monitor; el monitor alimenta el **panel web** (React) y las actualizaciones **WebSocket**. Los componentes opcionales incluyen la **API PHP** (Slim), **MySQL** (self-service / registro de dispositivos) y el **proxy hotspot** (UDP entre hotspots y el peer server — **integrado en `adn-server.py`** por defecto; `adn-proxy` independiente queda para layouts legados).
Este capítulo documenta la pila **adn-monitor** con el mismo nivel de detalle que las guías del servidor. El código fuente está en el repositorio **adn-monitor**, no en el repositorio **adn-server** (donde se mantiene esta documentación).
Este capítulo documenta la pila **adn-monitor** con el mismo nivel de detalle que las guías del servidor. El código fuente está en el repositorio **adn-monitor**, no en el repositorio **adn-server** (donde se mantiene esta documentación).
@ -11,16 +11,17 @@ Este capítulo documenta la pila **adn-monitor** con el mismo nivel de detalle q
| **`monitor/monitor.py`** | Python (Twisted): se conecta al **puerto TCP de informes** del peer server, decodifica cargas netstring (`CONFIG_SND`, `BRIDGE_SND`, `BRDG_EVENT`), mantiene **CTABLE** / **BTABLE**, escribe **Last Heard** / estadísticas de TG en **MySQL** si está configurado, sirve JSON **WebSocket** al panel. |
| **`monitor/monitor.py`** | Python (Twisted): se conecta al **puerto TCP de informes** del peer server, decodifica cargas netstring (`CONFIG_SND`, `BRIDGE_SND`, `BRDG_EVENT`), mantiene **CTABLE** / **BTABLE**, escribe **Last Heard** / estadísticas de TG en **MySQL** si está configurado, sirve JSON **WebSocket** al panel. |
| **`backend/`** | PHP **Slim**: `/api/config/dashboard`, auth, APIs **self-service** opcionales, proxy de alias. Lee **`adn-monitor.yaml`** vía **`ADN_CONFIG_PATH`**. |
| **`backend/`** | PHP **Slim**: `/api/config/dashboard`, auth, APIs **self-service** opcionales, proxy de alias. Lee **`adn-monitor.yaml`** vía **`ADN_CONFIG_PATH`**. |
| **`frontend/`** | React (Vite): UI del panel; consume API del backend + WebSocket. |
| **`frontend/`** | React (Vite): UI del panel; consume API del backend + WebSocket. |
| **`proxy/`** | Python (Twisted): **proxy hotspot** UDP; reenvía Homebrew entre hotspots y el peer server; lee **`Clients`** en MySQL para opciones **RPTO** (self-service). Carga **`adn-proxy.yaml`** por defecto (ver [Proxy hotspot](hotspot-proxy.md)). |
| **`proxy/`** | Python (Twisted): proxy hotspot UDP **independiente** (legado); reenvía Homebrew entre hotspots y el rango de puertos del peer server; lee **`Clients`** en MySQL para **RPTO**. Preferir **`PROXY`** integrado en **`adn-server.yaml`** — ver [Proxy hotspot](hotspot-proxy.md). |
## Ficheros de configuración
## Ficheros de configuración
| Fichero | Quién lo usa | Variable típica |
| Fichero | Quién lo usa | Variable típica |
|---------|----------------|-----------------|
|---------|----------------|-----------------|
| **`adn-server.yaml`** | **`adn-server.py`** (**`PROXY`** / **`SELF_SERVICE`** integrados) | `-c` / ruta por defecto junto al binario |
**`SELF_SERVICE`** (MySQL / PBKDF2) debe **coincidir** entre ambos YAML cuando separas la config. **`ADN_CONNECTION`**, panel, WebSocket y alias van en **`adn-monitor.yaml`**; los ajustes **`PROXY`** de escucha/master/rango van en **`adn-proxy.yaml`**, salvo que uses un **fichero único legado** vía **`ADN_CONFIG_PATH`** para el proxy.
**`SELF_SERVICE`** (MySQL / PBKDF2) debe **coincidir** entre **`adn-server.yaml`** (proxy integrado), **`adn-monitor.yaml`** y **`adn-proxy.yaml`** legado si se usa. **`ADN_CONNECTION`**, panel, WebSocket y alias van en **`adn-monitor.yaml`**; **`PROXY`** / **`SELF_SERVICE`** integrados van en **`adn-server.yaml`**; el proxy independiente sigue en **`adn-proxy.yaml`**.
**Se recarga:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (sin reiniciar el proceso), parámetros por system, **systems nuevos/eliminados** (incluida expansión `GENERATOR` y OBP nuevos), y cambios de IP/puerto (solo reinicia el listener de ese system).
**Se recarga:** `GLOBAL`, `REPORTS`, `ALIASES`, **`LOGGER.LOG_LEVEL`** (sin reiniciar el proceso), **`PROXY`** (timeouts, debug, listas de bloqueo — no bind ni destino), **`SELF_SERVICE`** (fusionado; activar/desactivar bucles BD requiere reinicio), parámetros por system, **systems nuevos/eliminados** (incluida expansión/colapso`GENERATOR` y OBP nuevos), y cambios de IP/puerto (solo reinicia el listener de ese system).
**No se recarga:** `adn-voice.yaml` (loop aparte cada 15 s), código Python, ficheros de alias (recarga periódica). La tabla **BRIDGES** no se reconstruye — reinicia si cambiaste reglas de bridge que exijan reset completo.
**No se recarga:** `adn-voice.yaml` (loop aparte cada 15 s), código Python, ficheros de alias (recarga periódica). La tabla **BRIDGES** no se reconstruye — reinicia si cambiaste reglas de bridge que exijan reset completo.**`PROXY.LISTEN_PORT`**, **`LISTEN_IP`** y **`TARGET_SYSTEM`** requieren **reinicio completo** para aplicarse.
**Secretos:** no versionar passphrases reales, URLs de seguridad ni `user_passwords.json` / `encryption_key.secret`. Usa placeholders en plantillas y mantén producción en local.
**Secretos:** no versionar passphrases reales, URLs de seguridad ni `user_passwords.json` / `encryption_key.secret`. Usa placeholders en plantillas y mantén producción en local.
@ -115,16 +115,16 @@ Aparecen principalmente en **MASTER** (y a menudo en **PEER**). OpenBridge usa u
| Clave | Significado |
| Clave | Significado |
|-------|-------------|
|-------|-------------|
| **REPEAT** | Si es true, el tráfico recibido puede **repetirse** a otros peers conectados al MASTER (comportamiento típico de conferencia). |
| **REPEAT** | Si es true, el tráfico recibido puede **repetirse** a otros peers conectados al MASTER (comportamiento típico de conferencia). |
| **MAX_PEERS** | Máximo de hotspots conectados. |
| **MAX_PEERS** | Máximo de hotspots conectados. En el MASTER **destino del proxy**, limita sesiones fan-in simultáneas. |
| **EXPORT_AMBE** | Flag de exportación AMBE (si está habilitado en el build). |
| **EXPORT_AMBE** | Flag de exportación AMBE (si está habilitado en el build). |
| **SINGLE_MODE** | Afecta a OPTIONS / expansión del generador (estilo un solo usuario). |
| **SINGLE_MODE** | Afecta a OPTIONS / expansión del generador (estilo un solo usuario). |
| **VOICE_IDENT** | Habilita **identificación por voz** periódica cuando se cumplen condiciones (ver `IdentUseCases`). |
| **VOICE_IDENT** | Habilita **identificación por voz** periódica cuando se cumplen condiciones (ver `IdentUseCases`). |
| **TS1_STATIC** / **TS2_STATIC** | Listas estáticas de TG separadas por comas, enviadas vía manejo OPTIONS (ver `options_config`). |
| **TS1_STATIC** / **TS2_STATIC** | Listas estáticas de TG separadas por comas, enviadas vía manejo OPTIONS (ver `options_config`). |
| **DEFAULT_REFLECTOR** | Número de **reflector** por defecto para bridges de marcado `#` (0 = ninguno). |
| **DEFAULT_REFLECTOR** | Número de **reflector** por defecto para bridges de marcado `#` (0 = ninguno). |
| **OVERRIDE_IDENT_TG** | TG opcional para ident por voz en lugar de all-call. |
| **OVERRIDE_IDENT_TG** | TG opcional para ident por voz en lugar de all-call. |
| **GENERATOR** | Si es **> 1**, este MASTER se expande en **`NAME-0`**, **`NAME-1`**, … con puertos consecutivos (ver `expand_generator` en código). |
| **GENERATOR** | Si es **> 1**, este MASTER se expande en **`NAME-0`**, **`NAME-1`**, … con puertos consecutivos (ver `expand_generator` en código). El **`adn-proxy`** independiente legado usaba el mismo rango; el proxy **integrado** usa **`PROXY.TARGET_SYSTEM`** solo inyección (sin puertos UDP por hotspot en el servidor). |
**MASTER** escucha conexiones PEER; cada peer autenticado se guarda en **`PEERS`** en tiempo de ejecución.
**MASTER** escucha conexiones PEER (salvo que sea el destino **solo inyección** del proxy — ver [Proxy hotspot](hotspot-proxy.md)); cada peer autenticado se guarda en **`PEERS`** en tiempo de ejecución.
---
---
@ -186,6 +186,28 @@ Detalle: [Monitor e informes](monitoring.md).
---
---
## `PROXY` (proxy hotspot integrado)
Se arranca siempre que exista un bloque **`PROXY`** (ver `adn-server.example.yaml`). Los hotspots se conectan a **`LISTEN_PORT`**; el tráfico se inyecta en **`TARGET_SYSTEM`**. Guía completa: [Proxy hotspot](hotspot-proxy.md).
| Clave | Significado |
|-------|-------------|
| **LISTEN_PORT** / **LISTEN_IP** | Bind UDP para conexiones de hotspots. |
| **TARGET_SYSTEM** | Nombre del **MASTER** que recibe HBP inyectado. Ese system pasa a **solo inyección** (`IP` / `PORT` eliminados al cargar). |
| **TIMEOUT** | Timeout de sesión inactiva (segundos). |
| **DEBUG** / **CLIENT_INFO** | Verbosidad de logs. |
| **BLACK_LIST** / **IP_BLACK_LIST** | Bloqueo de IDs de radio o IPs de cliente. |
**No** ejecutes **`adn-proxy`** independiente en el mismo **`LISTEN_PORT`** si el proxy integrado está activo.
---
## `SELF_SERVICE` (MySQL / opciones del panel)
Opcional; requiere `pip install -e ".[selfservice]"` con **`USE_SELFSERVICE: true`**. Usa la misma tabla **`Clients`** y parámetros PBKDF2 que **adn-monitor**. Las claves coinciden con la documentación del monitor — ver [Self-service](../../monitor/self-service.md) y [Proxy hotspot](hotspot-proxy.md#claves-self_service).
---
## `LOGGER`
## `LOGGER`
Implementado en `infrastructure/logging_config.py` (`setup_logging`). Los valores se leen del bloque **`LOGGER`** (o `--logging` solo para **LOG_LEVEL**).
Implementado en `infrastructure/logging_config.py` (`setup_logging`). Los valores se leen del bloque **`LOGGER`** (o `--logging` solo para **LOG_LEVEL**).
@ -247,3 +269,4 @@ Usa el intérprete del proyecto (ver reglas del workspace), p. ej. `python3.11`
- [Bridges y talkgroups](bridges-and-talkgroups.md) — semántica de `BRIDGES`.
- [Bridges y talkgroups](bridges-and-talkgroups.md) — semántica de `BRIDGES`.
- [Números especiales](special-numbers.md) — TG e IDs reservados.
- [Números especiales](special-numbers.md) — TG e IDs reservados.
**ADN DMR Peer Server** incluye un **proxy hotspot integrado**: un solo proceso (`adn-server.py`) acepta Homebrew (HBP) de muchos hotspots en un único puerto UDP e **inyecta** el tráfico en un **MASTER** configurado. **No** hace falta un proceso **`adn-proxy`** aparte cuando este modo está activo.
La configuración está en **`adn-server.yaml`**, bloques **`PROXY`** y opcional **`SELF_SERVICE`** (misma tabla MySQL **`Clients`** que **adn-monitor**).
---
## Cuándo usarlo
| Despliegue | Qué ejecutar |
|------------|--------------|
| **Stack ADN habitual** (monitor + panel + muchos hotspots Pi-Star) | **`adn-server.py`** con **`PROXY`** + **`SELF_SERVICE`** — desactiva la unidad **`adn-proxy`** independiente para evitar conflicto en **`PROXY.LISTEN_PORT`**. |
| **Legado / config separada** | **`proxy/proxy.py`** en el repo **adn-monitor** — ver [Proxy hotspot (independiente)](../../monitor/hotspot-proxy.md). |
El proxy integrado usa **fan-in**: los hotspots solo necesitan **`PROXY.LISTEN_PORT`** (p. ej. **62031**). El **MASTER** destino es **solo inyección** — **no** abre su propio puerto UDP para ese system (sin rango de puertos por hotspot en el host del servidor).
---
## Dependencia opcional (self-service)
El self-service con MySQL requiere **`mysqlclient`**:
```bash
pip install -e ".[selfservice]"
```
Si **`USE_SELFSERVICE: true`** pero falta **`mysqlclient`**, el arranque falla con un error claro. Pon **`USE_SELFSERVICE: false`** para usar el proxy sin BD (sin actualizaciones **RPTO** desde el panel).
---
## Claves `PROXY`
| Clave | Rol |
|-------|-----|
| **LISTEN_PORT** | Puerto UDP al que se conectan los **hotspots** (el que configuran en el dispositivo). |
| **LISTEN_IP** | Dirección de bind; vacío = todas las interfaces. |
| **TARGET_SYSTEM** | Nombre del **MASTER** en **`SYSTEMS`** que recibe el HBP inyectado (debe existir y estar **ENABLED**). |
| **TIMEOUT** | Timeout de sesión inactiva (segundos); las sesiones caducadas se eliminan en el MASTER. |
| **DEBUG** | Log detallado de paquetes. |
| **CLIENT_INFO** | Log de conexión/desconexión por ID de radio. |
| **BLACK_LIST** | Bloquea IDs de radio listados. |
| **IP_BLACK_LIST** | Bloquea IPs origen (con caducidad opcional). |
En **`PROXY`** integrado **no** hay **`MASTER`**, **`PORT`** ni **`GENERATOR`** — eso corresponde al proxy independiente legado. El MASTER destino usa **`MAX_PEERS`** (no un rango UDP) para limitar hotspots simultáneos.
Ejemplo (de `adn-server.example.yaml`):
```yaml
PROXY:
LISTEN_PORT: 62031
LISTEN_IP: ""
TARGET_SYSTEM: SYSTEM
TIMEOUT: 30
DEBUG: false
CLIENT_INFO: true
BLACK_LIST: []
IP_BLACK_LIST: {}
```
### MASTER destino solo inyección
Cuando **`PROXY.TARGET_SYSTEM`** apunta a un system (p. ej. **`SYSTEM`**), al arrancar se **eliminan****`IP`** / **`PORT`** de ese bloque MASTER. Los hotspots nunca se conectan al puerto de conferencia; todo el HBP entra por **`LISTEN_PORT`**.
Define **`MAX_PEERS`** en el MASTER destino como máximo de hotspots simultáneos (p. ej. **102**). Otros MASTER (**ECHO**, **D-APRS**, etc.) mantienen **`IP`** / **`PORT`** normales si no son el destino del proxy.
---
## Claves `SELF_SERVICE`
Misma semántica que **`adn-monitor.yaml`** / **`adn-proxy.yaml`** legado — tabla **`Clients`** compartida, flag **`modified`**, **RPTO** hacia el MASTER.
| Clave | Rol |
|-------|-----|
| **USE_SELFSERVICE** | Activa sincronización de opciones con MySQL (`true` / `false`). |
| **PBKDF2_SALT**, **PBKDF2_ITERATIONS** | Deben **coincidir** con monitor/backend para el hash de contraseñas. |
Al arrancar el servidor registra **`(SELF_SERVICE) Database connection test: OK`** y **`(SELF_SERVICE) Enabled`** si el pool conecta. El self-service es **asíncrono**; el reenvío de voz no se bloquea por latencia de BD.
Detalle del flujo en el panel: [Self-service](../../monitor/self-service.md).
---
## Comportamiento con varios hotspots
- Cada hotspot autenticado es un **peer** en el MASTER de inyección con sus **OPTIONS** (TG estáticas). **Repeat** y el fan-out del monitor respetan **OPTIONS por peer** — el tráfico de un TG no se envía a peers que no lo tienen seleccionado.
- Los talkgroups **parrot / eco 9990–9999** omiten el filtro OPTIONS y vuelven al hotspot **llamante** (ver [Números especiales](special-numbers.md)).
---
## Recarga en caliente (`SIGHUP`)
**Se aplica sin reiniciar** (las sesiones activas del proxy se mantienen):
- **`SELF_SERVICE`:** se fusiona en config (cambios de credenciales en nuevas operaciones BD; los bucles no se reinician en reload)
**Requiere reinicio completo del proceso:**
- **`PROXY.LISTEN_PORT`** / **`LISTEN_IP`** (el cambio de bind se registra y se ignora en reload)
- **`PROXY.TARGET_SYSTEM`**
- Activar o desactivar **`USE_SELFSERVICE`** tras el arranque
Ver [Configuración — recarga en caliente](configuration.md#recarga-en-caliente-adn-serveryaml).
---
## Proxy independiente (legado)
El repo **adn-monitor** sigue incluyendo **`proxy/proxy.py`** para despliegues con relay UDP **separado** y **`adn-proxy.yaml`**. **No** ejecutes el proxy integrado y **`adn-proxy`** independiente en el mismo **`LISTEN_PORT`**.
---
## Ver también
- [Configuración](configuration.md) — referencia completa de **`adn-server.yaml`**.
- [Monitorización e informes](monitoring.md) — informes TCP, panel, rotación de logs.
| **Informes** | Canal TCP netstring hacia **adn-monitor** (y paneles compatibles): config, estado de bridges, eventos de llamada `BRDG_EVENT`. |
| **Informes** | Canal TCP netstring hacia **adn-monitor** (y paneles compatibles): config, estado de bridges, eventos de llamada (informe v2 JSON). |
| **Proxy hotspot** | Fan-in UDP integrado opcional (`PROXY` en `adn-server.yaml`) y **self-service** MySQL (`SELF_SERVICE`) para opciones de hotspot desde el panel. |
## Programas relacionados
## Programas relacionados
- **Parrot / reproducción** — punto de entrada aparte (`adn-parrot.py`) para grabar y reproducir; ver [Parrot](parrot.md).
- **Parrot / reproducción** — punto de entrada aparte (`adn-parrot.py`) para grabar y reproducir; ver [Parrot](parrot.md).
- **Proxy hotspot independiente** — **`adn-proxy`** legado en el repo **adn-monitor** si no usas el proxy integrado; ver [Proxy hotspot (independiente)](../../monitor/hotspot-proxy.md).
| **`adn-server`** / **`adn-parrot`** | **`LOGGER.LOG_FILE`** (los logs del proxy integrado van al mismo fichero) |
| **`adn-proxy`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** en `adn-proxy.yaml` |
| **`adn-proxy`** (independiente, legado) | **`LOG.PATH`** + **`LOG.LOG_FILE`** en `adn-proxy.yaml` — omitir si usas **`PROXY`** integrado en `adn-server.yaml` |
| **`adn-monitor`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** en `adn-monitor.yaml` |
| **`adn-monitor`** | **`LOG.PATH`** + **`LOG.LOG_FILE`** en `adn-monitor.yaml` |
Ejemplo de fragmento en **`/etc/logrotate.d/adn`** (adaptar rutas y nombres de unidad):
Ejemplo de fragmento en **`/etc/logrotate.d/adn`** (adaptar rutas y nombres de unidad):
@ -71,7 +71,7 @@ Ejemplo de fragmento en **`/etc/logrotate.d/adn`** (adaptar rutas y nombres de u
}
}
```
```
Repite **`postrotate`** con **`kill -USR2`** para las unidades **`adn-parrot`**, **`adn-proxy`** y **`adn-monitor`** si rotas sus logs en el mismo host. Usa el **PID** correcto (**`MainPID`** de systemd, pidfile, o el proceso que gestiones).
Repite **`postrotate`** con **`kill -USR2`** para **`adn-parrot`** y **`adn-monitor`** si rotas sus logs en el mismo host. Añade **`adn-proxy`** solo si sigues usando el proxy **independiente** (no hace falta con proxy integrado en **`adn-server`**). Usa el **PID** correcto (**`MainPID`** de systemd, pidfile, o el proceso que gestiones).
## Requisitos
## Requisitos
@ -80,4 +80,6 @@ Repite **`postrotate`** con **`kill -USR2`** para las unidades **`adn-parrot`**,
## Self-service y hotspots
## Self-service y hotspots
Los operadores que editan **opciones de dispositivo** desde el panel usan el flujo **self-service** (MySQL **`Clients`**, proxy **RPTO**). Está documentado en [Self-service](../../monitor/self-service.md); **no** forma parte solo del binario del peer server. Para la configuración del **proxy hotspot** (`PROXY` en **`adn-proxy.yaml`** por defecto), enlace al rango **UDP** del peer server y arranque del proceso, ver [Proxy hotspot](../../monitor/hotspot-proxy.md).
Los operadores que editan **opciones de dispositivo** desde el panel usan el flujo **self-service** (MySQL **`Clients`**, **RPTO** hacia el MASTER de conferencia). En despliegues actuales de **ADN DMR Peer Server** esto corre **dentro de `adn-server.py`**: configura **`SELF_SERVICE`** y **`PROXY`** en **`adn-server.yaml`** (ver [Proxy hotspot](hotspot-proxy.md)). Semántica del panel: [Self-service](../../monitor/self-service.md).
Los stacks legados pueden seguir usando **`adn-proxy`** independiente y **`adn-proxy.yaml`** — ver [Proxy hotspot (independiente)](../../monitor/hotspot-proxy.md). No ejecutes ambos en el mismo **`LISTEN_PORT`**.