- Reads **`PROXY`** and **`SELF_SERVICE`** from the same YAML.
- For each hotspot client, allocates a port in **`DESTPORT_START`…`DEST_PORT_END`** and forwards UDP to **`MASTER`**.
- 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`**.
- 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 **`adn-mon.yaml`**, MySQL self-service, and deployment 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).
**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).
**Details:** [Hotspot proxy](hotspot-proxy.md) (config keys, peer server port range, startup).
## Typical deployment topology
```text
[Hotspots] --UDP--> [Proxy :LISTEN_PORT] --UDP--> [Peer server :DESTPORT range]
[Hotspots] --UDP--> [Proxy :LISTEN_PORT] --UDP--> [Peer server :PORT..PORT+GENERATOR-1]
All components read the **same** YAML (default path often `monitor/adn-mon.yaml`; override with **`ADN_CONFIG_PATH`**). The example shipped in the **adn-monitor** repo is the authoritative template; keys below match `monitor/adn-mon.yaml` and `monitor/src/adn_monitor/infrastructure/config_loader.py` (internal names may differ).
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.
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).
---
@ -19,7 +23,7 @@ All components read the **same** YAML (default path often `monitor/adn-mon.yaml`
---
## `ADN_CONNECTION`
## `ADN_CONNECTION` {#adn_connection}
Must match the **ADN DMR Peer Server** reporting configuration.
@ -27,6 +31,7 @@ Must match the **ADN DMR Peer Server** reporting configuration.
|-----|---------|
| **ADN_IP** | Host/IP where the **peer server’s report TCP listener** is bound (from the monitor’s network view). |
| **ADN_PORT** | TCP port — must equal **`REPORTS.REPORT_PORT`** on the server and be reachable. |
| **HELLO_TIMEOUT_MS** | After TCP connect, how long to wait for opcode **`0xFF` HELLO** (JSON) from **new-adn-server**. If nothing arrives in time, the monitor treats the peer as **legacy** (pickled CONFIG/BRIDGE only). Default **1500** ms. See [Monitoring and reports](../server/user-guide/monitoring.md). |
---
@ -45,13 +50,16 @@ If the PHP backend cannot connect, **auth** and **self-service** API routes are
## `PROXY`
Hotspot **UDP proxy** — full guide: [Hotspot proxy](hotspot-proxy.md). Summary: forwards each client to **`MASTER:DESTPORT_START`…`DEST_PORT_END`**; the peer server must **listen** on that IP and port range (see also [Architecture](architecture.md)).
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)).
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)).
| Key | Meaning |
|-----|---------|
| **MASTER** | Peer server host (IP or DNS; resolved at proxy startup). |
| **LISTEN_PORT** / **LISTEN_IP** | Where the proxy accepts hotspot UDP (empty IP often means all interfaces). |
| **DESTPORT_START** / **DEST_PORT_END** | One port per proxied client toward **`MASTER`**. |
| **PORT** / **DESTPORT_START** | Base UDP port on **`MASTER`** (same as server SYSTEM **PORT**). |
| **GENERATOR** | Count of consecutive UDP ports on **`MASTER`** (same integer as server SYSTEM **GENERATOR**). |
| **TIMEOUT**, **STATS**, **DEBUG**, **CLIENT_INFO** | Behaviour and logging. |
The **hotspot proxy** log filename is set in **`proxy/adn-proxy.yaml`** under **LOGGER** as **`PROXY_LOG_FILE`** (see [Hotspot proxy](hotspot-proxy.md)).
---
## `WEBSOCKET_SERVER`
@ -107,7 +116,8 @@ Similar idea to the peer server: download **peer / subscriber / TGID** JSON and
## Environment
- **`ADN_CONFIG_PATH`**: Absolute path to `adn-mon.yaml` for monitor, backend, and proxy.
- **`ADN_CONFIG_PATH`**: Absolute path to **`adn-monitor.yaml`** for the **monitor** and **PHP backend**.
- **`ADN_PROXY_CONFIG_PATH`** (optional): Absolute path to **`adn-proxy.yaml`** for the hotspot proxy. If unset, the proxy falls back to **`ADN_CONFIG_PATH`** (legacy combined file), then to **`proxy/adn-proxy.yaml`** by default — details in [Hotspot proxy](hotspot-proxy.md#configuration-file).
- Backend may use **`API_BASE_PATH`** if the API is mounted under a prefix.
There is no single mandatory layout for every deployment, but **today the proxy lives in the adn-monitor repo** on purpose:
- **Same config and ops** as the dashboard stack: **`adn-mon.yaml`**, **`ADN_CONFIG_PATH`**, and usually the same host as **PHP** and **MySQL**.
- **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**.
- **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.
@ -16,34 +16,40 @@ There is no single mandatory layout for every deployment, but **today the proxy
---
## Configuration file (same as monitor)
## Configuration file {#configuration-file}
The proxy does **not** use `adn-server.yaml`. It reads the **monitor** YAML:
The proxy does **not** use `adn-server.yaml`. It reads YAML that contains **`PROXY`**, **`SELF_SERVICE`**, and **`LOGGER`** (proxy log).
| Source | Purpose |
|--------|---------|
| **`ADN_CONFIG_PATH`** | Environment variable: absolute path to **`adn-mon.yaml`** (shared with **monitor**, **PHP backend**, optional **`.env`** in repo root). |
| **`python proxy/proxy.py --config /path/to/adn-mon.yaml`** | Overrides the path for this process only. |
| **Default** (if unset) | `../monitor/adn-mon.yaml` relative to the `proxy/` directory when run from the adn-monitor tree. |
### Resolution order
Sections used:
| Priority | Source | Purpose |
|----------|--------|---------|
| 1 | **`python proxy/proxy.py --config /path/to/file.yaml`** | Overrides config path for this process only. |
| 3 | **`ADN_CONFIG_PATH`** | Legacy: absolute path to a **combined** file (e.g. **`adn-monitor.yaml`** with **PROXY** embedded — same as monitor/backend). |
| 4 | **Default** | **`proxy/adn-proxy.yaml`** next to `proxy/proxy.py` when neither env var is set. |
Copy **`proxy/adn-proxy.example.yaml`** to **`proxy/adn-proxy.yaml`** and edit. **`SELF_SERVICE`** must match **`monitor/adn-monitor.yaml`** (same DB credentials and PBKDF2 parameters).
- **`SELF_SERVICE`** — MySQL and **`USE_SELFSERVICE`** (for **`Clients`** table, RPTO / options).
- **`LOGGER`** — **`LOG_PATH`** and **`PROXY_LOG_FILE`** (proxy log is separate from **`LOG_FILE`** used by `monitor.py`).
- **`LOGGER`** — **`LOG_PATH`** and **`PROXY_LOG_FILE`** (separate from **`LOG_FILE`** in `adn-monitor.yaml` for`monitor.py`).
Optional **environment** overrides (see `proxy/README.md` in the repo): e.g. **`ADN_PROXY_DEBUG`**, **`ADN_PROXY_LISTENPORT`**.
---
## `PROXY` keys (`adn-mon.yaml`)
## `PROXY` keys (in `adn-proxy.yaml`, or legacy combined YAML)
| Key | Role |
|-----|------|
| **MASTER** | IP or **hostname** of the **ADN DMR Peer Server** host. Resolved to an IPv4 address at startup (Twisted requires an IP for `write()`). |
| **LISTEN_PORT** | UDP port where **hotspots** connect **to the proxy** (the address users configure on the hotspot). |
| **LISTEN_IP** | Empty often means all interfaces; otherwise bind to this address. |
| **DESTPORT_START** / **DEST_PORT_END** | Inclusive range of UDP ports on **`MASTER`** used **one per proxied hotspot** (sequential allocation inside the proxy). |
| **PORT** / **DESTPORT_START** | Base UDP port on **`MASTER`** (alias **DESTPORT_START**); must match **`SYSTEM.PORT`** in `adn-server`. |
| **GENERATOR** | Same integer as **`SYSTEM.GENERATOR`**; UDP ports **`PORT`…`PORT+GENERATOR-1`** on **`MASTER`** (one per proxied hotspot session). |
## Peer server (`adn-server.yaml`) must cover the port range
The proxy forwards traffic to **`MASTER:DESTPORT`** for each client, where **DESTPORT** is chosen inside **[DESTPORT_START, DEST_PORT_END]**.
The proxy forwards traffic to **`MASTER:assigned_port`** for each client, where **assigned_port** is picked from **`PORT`…`PORT+GENERATOR-1`** (same **PORT**/**GENERATOR** semantics as [Server configuration](../server/user-guide/configuration.md)).
The **ADN DMR Peer Server** must therefore **listen on UDP** on **that host** for **every port** in the range that you intend to use (one **MASTER** listener per port, or equivalent).
The **ADN DMR Peer Server** must **listen on UDP** on **that host** for **every port** in that range (usually via **`GENERATOR`** on one SYSTEM block).
- A**single**`MODE: MASTER` with **one**`PORT` is **not** enough for multiple proxy clients if they map to different **DESTPORT** values — you need **multiple listeners** on the range.
- Typical approaches: **`GENERATOR`** on a MASTER system (splits into `NAME-0`, `NAME-1`, … with consecutive **PORT** values — see [Server configuration](../server/user-guide/configuration.md)), and/or multiple **`SYSTEMS`** entries, aligned with **`DESTPORT_START`…`DEST_PORT_END`** in **`PROXY`**.
- Align **`PROXY.PORT`** and **`PROXY.GENERATOR`** with **`SYSTEM.PORT`** and **`SYSTEM.GENERATOR`** in **`adn-server.yaml`**.
- Typical setup: one **`MODE: MASTER`** entry with **`GENERATOR`** expanding to `SYSTEM-0`…`SYSTEM-(N-1)` on consecutive UDP ports — see [Server configuration](../server/user-guide/configuration.md).
If the server only listens on e.g. **56400** but the proxy sends to **56401**, that client will not register.
@ -69,18 +75,27 @@ If the server only listens on e.g. **56400** but the proxy sends to **56401**, t
## How the process starts
1. Resolve config path (`ADN_CONFIG_PATH`, `--config`, or default).
1. Resolve config path (`--config`, **`ADN_PROXY_CONFIG_PATH`**, **`ADN_CONFIG_PATH`**, or default **`proxy/adn-proxy.yaml`**).
Use **systemd** or another supervisor to run alongside **`monitor.py`** and the **PHP** stack.
@ -103,12 +118,12 @@ Details: [Self-service](self-service.md) and the **adn-monitor** `proxy/README.m
## Monitor visibility
Hotspots appear on the dashboard only if the **peer server** sends **TCP reports** to the same host/port as **`ADN_CONNECTION`** in **`adn-mon.yaml`**. Align **`REPORTS`** on the server with **`ADN_IP` / `ADN_PORT`**. See [Monitoring and reports](../server/user-guide/monitoring.md).
Hotspots appear on the dashboard only if the **peer server** sends **TCP reports** to the same host/port as **`ADN_CONNECTION`** in **`adn-monitor.yaml`**. Align **`REPORTS`** on the server with **`ADN_IP` / `ADN_PORT`**. See [Monitoring and reports](../server/user-guide/monitoring.md).
---
## See also
- [Monitor configuration](configuration.md) — full **`adn-mon.yaml`** reference (PROXY section summary).
- [Monitor configuration](configuration.md) — **`adn-monitor.yaml`** (dashboard, reports, MySQL for backend/monitor); **`PROXY`** detail above.
- [Architecture](architecture.md) — where the proxy sits in the stack.
| **`proxy/`** | Python (Twisted): UDP **hotspot proxy**; forwards Homebrew between hotspots and the peer server; reads **`Clients`** in MySQL for **RPTO** options (self-service). |
| **`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)). |
## Single configuration file
## Configuration files
**`adn-mon.yaml`** (path often set with **`ADN_CONFIG_PATH`** in `.env`) is shared by:
| **`proxy/adn-proxy.yaml`** | **`proxy/proxy.py`** | **`ADN_PROXY_CONFIG_PATH`** (optional; defaults and legacy fallback in [Hotspot proxy](hotspot-proxy.md#configuration-file)) |
- Python monitor (`monitor.py`)
- PHP backend (`backend/public/index.php`)
- Hotspot proxy (`proxy/proxy.py`)
So **one** YAML drives reporting addresses, dashboard strings, WebSocket port, **SELF_SERVICE** DB credentials, and **PROXY** listen/range settings.
**`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.
## Link to the peer server
| Server (`adn-server.yaml`) | Monitor (`adn-mon.yaml`) |
| Server (`adn-server.yaml`) | Monitor (`adn-monitor.yaml`) |
| **`REPORTS.REPORT_CLIENTS`** — list of IPs allowed to connect **to** the report listener, or the monitor host | **`ADN_CONNECTION.ADN_IP`** / **`ADN_PORT`** — where the **monitor connects** (must match the server’s report bind and port). |
| **`REPORTS.REPORT_PORT`** — TCP port the **server listens on** for incoming report connections | Same port as **`ADN_PORT`**. |
See [Monitoring and reports](../server/user-guide/monitoring.md) for report opcodes and [Monitor configuration](configuration.md) for every `adn-mon.yaml` section.
See [Monitoring and reports](../server/user-guide/monitoring.md) for report opcodes and [Monitor configuration](configuration.md) for every `adn-monitor.yaml` section.
## See also
- [Hotspot proxy](hotspot-proxy.md) — `PROXY`, peer server port range, how the process loads config and runs
1. **`SELF_SERVICE`** block in **`adn-mon.yaml`** with valid **MySQL** credentials and **PBKDF2** parameters matching your password tooling (same salt/iterations as **`hotspot_proxy_self_service.py`** when used).
1. **`SELF_SERVICE`** block in **`adn-monitor.yaml`** with valid **MySQL** credentials and **PBKDF2** parameters matching your password tooling (same salt/iterations as **`hotspot_proxy_self_service.py`** when used).
2. **`DASHBOARD.SELF_SERVICE: true`** so the UI shows the **Self-service** menu entry (and the backend exposes `/api/self-service/*` when DB connects).
3. **`Clients`** table populated with rows: **`callsign`**, **`int_id`** (DMR ID), **`psswd`** (PBKDF2-SHA256 hex), **`options`** (semicolon-separated `KEY=value`), **`logged_in`**, **`host`**, **`modified`**, etc. (see adn-monitor DB schema / migration scripts in the repo).
4. Hotspot traffic should pass through the **proxy** if you rely on **`modified`** and **RPTO** push (see flow below).
**ADN Systems DMR Peer Server** is derived from **FreeDMR**, reorganised with **clean architecture** (domain, application, infrastructure) and ADN-specific features: scheduled announcements, **TTS**, on-demand voice, **`adn-voice.yaml`** merge, TCP reporting to **ADN Monitor**, integration with **`adn-mon.yaml`**, self-service, hotspot proxy, and more.
**ADN Systems DMR Peer Server** is derived from **FreeDMR**, reorganised with **clean architecture** (domain, application, infrastructure) and ADN-specific features: scheduled announcements, **TTS**, on-demand voice, **`adn-voice.yaml`** merge, TCP reporting to **ADN Monitor**, integration with **`adn-monitor.yaml`**, self-service, hotspot proxy, and more.
**[FreeDMR Peer Server](https://gitlab.hacknix.net/hacknix/FreeDMR)** is by **Simon Adlem, G7RZU** ([hacknix](https://gitlab.hacknix.net/hacknix/FreeDMR)).
When **`REPORTS`** is enabled in the server config, the **ADN DMR Peer Server** listens on TCP and **report clients** (typically **adn-monitor**) connect and receive:
- **CONFIG_SND** / **BRIDGE_SND** — pickled snapshots of systems and bridges.
- **HELLO** (opcode **`0xFF`**) — JSON sent **first** on each new TCP connection by **new-adn-server** (`adn-server`): `server` name, package **`version`**, **`protocol`** number, and **`features`** (e.g. `INGRESS`, `END_TX_FORWARD`, `PUSH_ON_CONNECT`). Lets the monitor tag the session as **v2** before any pickled payloads.
- **CONFIG_SND** / **BRIDGE_SND** — pickled snapshots of systems and bridges (sent immediately after HELLO on connect, and again on updates / request).
- **BRDG_EVENT** — text events for calls (`GROUP VOICE`, `PRIVATE VOICE`, etc.).
Older stacks (**legacy** `adn-dmr-server`-style) may **omit** HELLO. **adn-monitor** waits up to **`ADN_CONNECTION.HELLO_TIMEOUT_MS`** (see [Monitor configuration](../../monitor/configuration.md#adn_connection)); if no HELLO arrives, it assumes **legacy** reporting.
The **monitor** decodes these messages, updates its **CTABLE** / **BTABLE**, and (when MySQL is configured) persists Last Heard / statistics.
| `(REPORT) No HELLO in …s; assuming legacy adn-dmr-server …` | No **`0xFF`** before timeout — monitor keeps **legacy** mode (pickled CONFIG/BRIDGE only). Expected if the peer is classic **`adn-dmr-server`**. If you **know** the server is **new-adn-server** but still see this, check **`ADN_IP`** / **`ADN_PORT`**, **`REPORTS.REPORT_CLIENTS`**, firewalls, or raise **`HELLO_TIMEOUT_MS`** slightly on very slow links. |
At **WARNING**: invalid HELLO JSON (`(REPORT) HELLO payload not valid JSON`), or **`Invalid GLOBAL.TIMEZONE`** if **`GLOBAL.TIMEZONE`** in YAML is not a valid IANA name.
## OpenBridge monitor semantics
- **`GROUP VOICE,INGRESS,RX`** — first sight of a stream on an OpenBridge **leg** (debug; full visibility in logs).
@ -26,4 +43,4 @@ The dashboard shows **operational** state from **START** (canonical); the **Moni
## 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-mon.yaml`), 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`**, 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).
- Lee **`PROXY`** y **`SELF_SERVICE`** del mismo YAML.
- Por cada cliente hotspot, asigna un puerto en **`DESTPORT_START`…`DEST_PORT_END`** y reenvía UDP a **`MASTER`**.
- 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`**.
- 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 **`adn-mon.yaml`**, self-service MySQL e implantación 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).
**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).
**Detalle:** [Proxy hotspot](hotspot-proxy.md) (claves de config, rango de puertos del peer, arranque).
## Topología típica de despliegue
```text
[Hotspots] --UDP--> [Proxy :LISTEN_PORT] --UDP--> [Peer server :rango DESTPORT]
[Hotspots] --UDP--> [Proxy :LISTEN_PORT] --UDP--> [Peer server :PORT..PORT+GENERATOR-1]
Todos los componentes leen el **mismo** YAML (ruta por defecto a menudo `monitor/adn-mon.yaml`; se puede sobrescribir con **`ADN_CONFIG_PATH`**). El ejemplo del repositorio **adn-monitor** es la plantilla autoritativa; las claves siguientes coinciden con `monitor/adn-mon.yaml` y `monitor/src/adn_monitor/infrastructure/config_loader.py` (los nombres internos pueden diferir).
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.
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).
---
@ -27,6 +31,7 @@ Debe coincidir con la configuración de informes del **ADN DMR Peer Server**.
|-------|-------------|
| **ADN_IP** | Host/IP donde está el **listener TCP de informes** del peer server (vista de red desde el monitor). |
| **ADN_PORT** | Puerto TCP — debe ser igual a **`REPORTS.REPORT_PORT`** en el servidor y ser alcanzable. |
| **HELLO_TIMEOUT_MS** | Tras conectar por TCP, tiempo de espera del opcode **`0xFF` HELLO** (JSON) desde **new-adn-server**. Si no llega a tiempo, el monitor trata el peer como **legado** (solo CONFIG/BRIDGE pickle). Por defecto **1500** ms. Ver [Monitor e informes](../server/user-guide/monitoring.md). |
---
@ -45,13 +50,16 @@ Si el backend PHP no puede conectar, las rutas de **auth** y **self-service** no
## `PROXY`
**Proxy UDP hotspot** — guía completa: [Proxy hotspot](hotspot-proxy.md). Resumen: reenvía cada cliente a **`MASTER:DESTPORT_START`…`DEST_PORT_END`**; el peer server debe **escuchar** en esa IP y rango de puertos (ver también [Arquitectura](architecture.md)).
**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)).
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)).
| Clave | Significado |
|-------|-------------|
| **MASTER** | Host del peer server (IP o DNS; resuelto al arrancar el proxy). |
| **LISTEN_PORT** / **LISTEN_IP** | Dónde el proxy acepta UDP del hotspot (IP vacía suele significar todas las interfaces). |
| **DESTPORT_START** / **DEST_PORT_END** | Un puerto por cliente proxy hacia **`MASTER`**. |
| **PORT** / **DESTPORT_START** | Puerto UDP base en **`MASTER`** (el mismo que **PORT** del SYSTEM en el servidor). |
| **GENERATOR** | Cantidad de puertos UDP consecutivos en **`MASTER`** (el mismo entero que **GENERATOR** del SYSTEM en el servidor). |
| **TIMEOUT**, **STATS**, **DEBUG**, **CLIENT_INFO** | Comportamiento y registro. |
| **BLACK_LIST** / **IP_BLACK_LIST** | Listas de bloqueo opcionales. |
@ -74,10 +82,11 @@ Misma idea que en el peer server: descargar JSON de **peer / subscriber / TGID**
| Clave | Significado |
|-------|-------------|
| **LOG_PATH** | Directorio de ficheros de log. |
| **LOG_FILE** | Nombre del log del monitor (p. ej. `adn-mon.log`). |
| **PROXY_LOG_FILE** | Nombre de log separado para el proxy (cuando se ejecuta con logging del proxy). |
| **LOG_FILE** | Nombre del log del monitor (p. ej. `adn-monitor.log`). |
| **LOG_LEVEL** | p. ej. `INFO`, `DEBUG`. |
El nombre del fichero de log del **proxy hotspot** se define en **`proxy/adn-proxy.yaml`** dentro de **LOGGER** como **`PROXY_LOG_FILE`** (ver [Proxy hotspot](hotspot-proxy.md)).
---
## `WEBSOCKET_SERVER`
@ -107,7 +116,8 @@ Misma idea que en el peer server: descargar JSON de **peer / subscriber / TGID**
## Entorno
- **`ADN_CONFIG_PATH`**: ruta absoluta a `adn-mon.yaml` para monitor, backend y proxy.
- **`ADN_CONFIG_PATH`**: ruta absoluta a **`adn-monitor.yaml`** para el **monitor** y el **backend PHP**.
- **`ADN_PROXY_CONFIG_PATH`** (opcional): ruta absoluta a **`adn-proxy.yaml`** para el proxy hotspot. Si no está definida, el proxy usa **`ADN_CONFIG_PATH`** (fichero combinado legado), luego **`proxy/adn-proxy.yaml`** por defecto — detalles en [Proxy hotspot](hotspot-proxy.md#configuration-file).
- El backend puede usar **`API_BASE_PATH`** si la API va bajo un prefijo.
No hay un despliegue obligatorio único, pero **hoy el proxy vive en el repo adn-monitor** a propósito:
- **Misma config y operativa** que el panel: **`adn-mon.yaml`**, **`ADN_CONFIG_PATH`**, y normalmente el mismo host que **PHP** y **MySQL**.
- **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**.
- 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.
@ -16,34 +16,40 @@ No hay un despliegue obligatorio único, pero **hoy el proxy vive en el repo adn
---
## Fichero de configuración (igual que el monitor)
## Fichero de configuración {#configuration-file}
El proxy **no** usa `adn-server.yaml`. Lee el YAML del **monitor**:
El proxy **no** usa `adn-server.yaml`. Lee un YAML que incluye **`PROXY`**, **`SELF_SERVICE`** y **`LOGGER`** (log del proxy).
| Origen | Uso |
|--------|-----|
| **`ADN_CONFIG_PATH`** | Variable de entorno: ruta absoluta a **`adn-mon.yaml`** (compartida con **monitor**, **backend PHP**, **`.env`** opcional en la raíz del repo). |
| **`python proxy/proxy.py --config /ruta/a/adn-mon.yaml`** | Sobrescribe la ruta solo para este proceso. |
| **Por defecto** (sin definir) | `../monitor/adn-mon.yaml` relativo al directorio `proxy/` al ejecutar desde el árbol adn-monitor. |
### Orden de resolución
Secciones usadas:
| Prioridad | Origen | Uso |
|-----------|--------|-----|
| 1 | **`python proxy/proxy.py --config /ruta/fichero.yaml`** | Sobrescribe la ruta solo para este proceso. |
| 2 | **`ADN_PROXY_CONFIG_PATH`** | Variable opcional: ruta absoluta a **`adn-proxy.yaml`** (config dedicada del proxy). |
| 3 | **`ADN_CONFIG_PATH`** | Legado: ruta a un **fichero combinado** (p. ej. **`adn-monitor.yaml`** con **PROXY** incrustado — igual que monitor/backend). |
| 4 | **Por defecto** | **`proxy/adn-proxy.yaml`** junto a `proxy/proxy.py` si no hay variables de entorno. |
Copia **`proxy/adn-proxy.example.yaml`** a **`proxy/adn-proxy.yaml`** y edita. **`SELF_SERVICE`** debe coincidir con **`monitor/adn-monitor.yaml`** (mismas credenciales MySQL y PBKDF2).
Secciones leídas del fichero elegido:
- **`PROXY`** — dirección de escucha, host master, **rango** de puertos de destino, timeouts, debug, listas negras.
- **`SELF_SERVICE`** — MySQL y **`USE_SELFSERVICE`** (tabla **`Clients`**, RPTO / opciones).
- **`LOGGER`** — **`LOG_PATH`** y **`PROXY_LOG_FILE`** (log del proxy separado de **`LOG_FILE`** de `monitor.py`).
- **`LOGGER`** — **`LOG_PATH`** y **`PROXY_LOG_FILE`** (separado del**`LOG_FILE`** de`adn-monitor.yaml` para`monitor.py`).
**Entorno** opcional (ver `proxy/README.md` en el repo): p. ej. **`ADN_PROXY_DEBUG`**, **`ADN_PROXY_LISTENPORT`**.
---
## Claves `PROXY` (`adn-mon.yaml`)
## Claves `PROXY` (en `adn-proxy.yaml`, o YAML combinado legado)
| Clave | Rol |
|-------|-----|
| **MASTER** | IP o **nombre de host** del **ADN DMR Peer Server**. Se resuelve a IPv4 al arrancar (Twisted necesita IP para `write()`). |
| **LISTEN_PORT** | Puerto UDP donde los **hotspots** se conectan **al proxy** (lo que configuran en el hotspot). |
| **LISTEN_IP** | Vacío suele significar todas las interfaces; si no, enlazar a esa dirección. |
| **DESTPORT_START** / **DEST_PORT_END** | Rango inclusivo de puertos UDP en **`MASTER`**, **uno por hotspot** proxy (asignación secuencial dentro del proxy). |
| **PORT** / **DESTPORT_START** | Puerto UDP base en **`MASTER`** (alias **DESTPORT_START**); debe coincidir con **`SYSTEM.PORT`** en `adn-server`. |
| **GENERATOR** | El mismo entero que **`SYSTEM.GENERATOR`**; puertos UDP **`PORT`…`PORT+GENERATOR-1`** en **`MASTER`** (uno por sesión de hotspot proxy). |
| **TIMEOUT** | Tiempo de inactividad / sesión (segundos). |
| **STATS** | Registro extra de estadísticas. |
| **DEBUG** | Log detallado de paquetes (o **`ADN_PROXY_DEBUG=1`**). |
@ -56,12 +62,12 @@ Las claves internas tras la carga usan nombres mixtos (`Master`, `ListenPort`,
## El peer server (`adn-server.yaml`) debe cubrir el rango de puertos
El proxy reenvía tráfico a **`MASTER:DESTPORT`** por cliente, con **DESTPORT** en **[DESTPORT_START, DEST_PORT_END]**.
El proxy reenvía tráfico a **`MASTER:puerto_asignado`** por cliente; **puerto_asignado** se elige en **`PORT`…`PORT+GENERATOR-1`** (la misma semántica de **PORT**/**GENERATOR** que en [Configuración del servidor](../server/user-guide/configuration.md)).
El **ADN DMR Peer Server** debe **escuchar UDP** en **ese host** en **cada puerto** del rango que vayas a usar (un listener **MASTER** por puerto, o equivalente).
El **ADN DMR Peer Server** debe **escuchar UDP** en **ese host** en **cada puerto** de ese rango (normalmente mediante **`GENERATOR`** en un bloque SYSTEM).
- Un único `MODE: MASTER` con un solo **`PORT`** **no** basta para varios clientes proxy si usan **DESTPORT** distintos — hacen falta **varios listeners** en el rango.
- Enfoques típicos: **`GENERATOR`** en un sistema MASTER (se parte en `NAME-0`, `NAME-1`, … con **PORT** consecutivos — ver [Configuración del servidor](../server/user-guide/configuration.md)), y/o varias entradas **`SYSTEMS`**, alineadas con **`DESTPORT_START`…`DEST_PORT_END`** en **`PROXY`**.
- Alinea **`PROXY.PORT`** y **`PROXY.GENERATOR`** con **`SYSTEM.PORT`** y **`SYSTEM.GENERATOR`** en **`adn-server.yaml`**.
- Configuración típica: un **`MODE: MASTER`** con **`GENERATOR`** que expande a `SYSTEM-0`…`SYSTEM-(N-1)` en puertos UDP consecutivos — ver [Configuración del servidor](../server/user-guide/configuration.md).
Si el servidor solo escucha p. ej. en **56400** pero el proxy envía a **56401**, ese cliente no se registrará.
@ -69,18 +75,27 @@ Si el servidor solo escucha p. ej. en **56400** pero el proxy envía a **56401**
## Cómo arranca el proceso
1. Resolver ruta de config (`ADN_CONFIG_PATH`, `--config`, o por defecto).
1. Resolver ruta de config (`--config`, **`ADN_PROXY_CONFIG_PATH`**, **`ADN_CONFIG_PATH`**, o por defecto **`proxy/adn-proxy.yaml`**).
Usar **systemd** u otro supervisor junto a **`monitor.py`** y la pila **PHP**.
@ -103,12 +118,12 @@ Detalle: [Self-service](self-service.md) y **`proxy/README.md`** en adn-monitor.
## Visibilidad en el monitor
Los hotspots aparecen en el panel solo si el **peer server** envía **informes TCP** al mismo host/puerto que **`ADN_CONNECTION`** en **`adn-mon.yaml`**. Alinea **`REPORTS`** en el servidor con **`ADN_IP` / `ADN_PORT`**. Ver [Monitor e informes](../server/user-guide/monitoring.md).
Los hotspots aparecen en el panel solo si el **peer server** envía **informes TCP** al mismo host/puerto que **`ADN_CONNECTION`** en **`adn-monitor.yaml`**. Alinea **`REPORTS`** en el servidor con **`ADN_IP` / `ADN_PORT`**. Ver [Monitor e informes](../server/user-guide/monitoring.md).
---
## Ver también
- [Configuración del monitor](configuration.md) — referencia **`adn-mon.yaml`** (resumen PROXY).
- [Configuración del monitor](configuration.md) — **`adn-monitor.yaml`** (panel, informes, MySQL para backend/monitor); detalle **`PROXY`** arriba.
- [Arquitectura](architecture.md) — dónde encaja el proxy en la pila.
@ -9,32 +9,31 @@ Este capítulo documenta la pila **adn-monitor** con el mismo nivel de detalle q
| Parte | Rol |
|-------|-----|
| **`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 el **mismo**`adn-mon.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. |
| **`proxy/`** | Python (Twisted): **proxy hotspot** UDP; reenvía Homebrew entre hotspots y el peer server; lee **`Clients`** en MySQL para opciones **RPTO** (self-service). |
| **`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)). |
## Un solo fichero de configuración
## Ficheros de configuración
**`adn-mon.yaml`** (ruta a menudo con **`ADN_CONFIG_PATH`** en `.env`) lo comparten:
| **`proxy/adn-proxy.yaml`** | **`proxy/proxy.py`** | **`ADN_PROXY_CONFIG_PATH`** (opcional; valores por defecto y legado en [Proxy hotspot](hotspot-proxy.md#configuration-file)) |
- Monitor Python (`monitor.py`)
- Backend PHP (`backend/public/index.php`)
- Proxy hotspot (`proxy/proxy.py`)
Un **único** YAML define direcciones de informes, textos del panel, puerto WebSocket, credenciales **SELF_SERVICE** de la BD y ajustes **PROXY** de escucha/rango.
**`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.
| **`REPORTS.REPORT_CLIENTS`** — lista de IPs permitidas para conectar **al** listener de informes, o el host del monitor | **`ADN_CONNECTION.ADN_IP`** / **`ADN_PORT`** — a dónde **se conecta** el monitor (debe coincidir con el bind y puerto de informes del servidor). |
| **`REPORTS.REPORT_PORT`** — puerto TCP en el que el **servidor escucha** conexiones de informes | El mismo puerto que **`ADN_PORT`**. |
Ver [Monitor e informes](../server/user-guide/monitoring.md) para los opcodes de informes y [Configuración del monitor](configuration.md) para cada sección de `adn-mon.yaml`.
Ver [Monitor e informes](../server/user-guide/monitoring.md) para los opcodes de informes y [Configuración del monitor](configuration.md) para cada sección de `adn-monitor.yaml`.
## Ver también
- [Proxy hotspot](hotspot-proxy.md) — `PROXY`, rango de puertos del peer, carga de config y arranque
1. Bloque **`SELF_SERVICE`** en **`adn-mon.yaml`** con credenciales **MySQL** válidas y parámetros **PBKDF2** alineados con tu herramienta de contraseñas (misma sal/iteraciones que **`hotspot_proxy_self_service.py`** cuando se use).
1. Bloque **`SELF_SERVICE`** en **`adn-monitor.yaml`** con credenciales **MySQL** válidas y parámetros **PBKDF2** alineados con tu herramienta de contraseñas (misma sal/iteraciones que **`hotspot_proxy_self_service.py`** cuando se use).
2. **`DASHBOARD.SELF_SERVICE: true`** para que la UI muestre la entrada **Self-service** (y el backend exponga `/api/self-service/*` cuando la BD conecta).
3. Tabla **`Clients`** con filas: **`callsign`**, **`int_id`** (ID DMR), **`psswd`** (hex PBKDF2-SHA256), **`options`** (línea `KEY=value` separada por `;`), **`logged_in`**, **`host`**, **`modified`**, etc. (ver esquema / migraciones en el repo adn-monitor).
4. El tráfico del hotspot debe pasar por el **proxy** si dependes de **`modified`** y del envío **RPTO** (ver flujo abajo).
**ADN Systems DMR Peer Server** parte de **FreeDMR**, reorganizado con **arquitectura limpia** (dominio, aplicación, infraestructura) y con funciones propias de ADN: anuncios programados, **TTS**, voz bajo demanda, fusión de **`adn-voice.yaml`**, informes TCP al **ADN Monitor**, integración con **`adn-mon.yaml`**, self-service y proxy hotspot, entre otras.
**ADN Systems DMR Peer Server** parte de **FreeDMR**, reorganizado con **arquitectura limpia** (dominio, aplicación, infraestructura) y con funciones propias de ADN: anuncios programados, **TTS**, voz bajo demanda, fusión de **`adn-voice.yaml`**, informes TCP al **ADN Monitor**, integración con **`adn-monitor.yaml`**, self-service y proxy hotspot, entre otras.
**[FreeDMR Peer Server](https://gitlab.hacknix.net/hacknix/FreeDMR)** es obra de **Simon Adlem, G7RZU** ([hacknix](https://gitlab.hacknix.net/hacknix/FreeDMR)). El proyecto se describe así:
Cuando **`REPORTS`** está habilitado en la config del servidor, el **ADN DMR Peer Server** escucha en TCP y los **clientes de informes** (típicamente **adn-monitor**) se conectan y reciben:
- **CONFIG_SND** / **BRIDGE_SND** — instantáneas pickle de sistemas y bridges.
- **HELLO** (opcode **`0xFF`**) — JSON enviado **el primero** en cada conexión TCP por **new-adn-server** (`adn-server`): nombre **`server`**, **`version`** del paquete, número de **`protocol`** y lista **`features`** (p. ej. `INGRESS`, `END_TX_FORWARD`, `PUSH_ON_CONNECT`). Permite al monitor marcar la sesión como **v2** antes de las cargas pickle.
- **CONFIG_SND** / **BRIDGE_SND** — instantáneas pickle de sistemas y bridges (tras HELLO al conectar, y de nuevo en actualizaciones / petición).
- **BRDG_EVENT** — eventos de texto para llamadas (`GROUP VOICE`, `PRIVATE VOICE`, etc.).
Las pilas antiguas (**legado** estilo `adn-dmr-server`) pueden **omitir** HELLO. **adn-monitor** espera hasta **`ADN_CONNECTION.HELLO_TIMEOUT_MS`** (ver [Configuración del monitor](../../monitor/configuration.md#adn_connection)); si no llega HELLO, asume informes **legacy**.
El **monitor** decodifica estos mensajes, actualiza **CTABLE** / **BTABLE** y (con MySQL configurado) persiste Last Heard / estadísticas.
**Pila completa:** [Descripción general del ADN Monitor](../../monitor/index.md) (monitor Python, WebSocket, API PHP, proxy y self-service opcionales).
### Líneas de log del canal de informes (logger `adn-monitor`)
Python usa el nombre de logger **`adn-monitor`** (ver **`LOGGER.LOG_FILE`** en `adn-monitor.yaml`). **INFO** típicos del cliente TCP de informes:
| Prefijo / texto del log | Significado |
|-------------------------|-------------|
| `(REPORT) Connection to report server established` | Sesión TCP activa; arranca la espera de HELLO (**`HELLO_TIMEOUT_MS`**). |
| `(REPORT) stringReceived: HELLO opcode=ff …` | Trama HELLO cruda en el cable. |
| `(REPORT) No HELLO in …s; assuming legacy adn-dmr-server …` | No hay **`0xFF`** antes del timeout — modo **legacy** (solo CONFIG/BRIDGE pickle). Normal si el peer es **`adn-dmr-server`** clásico. Si **sabes** que el servidor es **new-adn-server** y aún ves esto, revisa **`ADN_IP`** / **`ADN_PORT`**, **`REPORTS.REPORT_CLIENTS`**, cortafuegos, o sube un poco **`HELLO_TIMEOUT_MS`** en enlaces muy lentos. |
En **WARNING**: JSON HELLO inválido (`(REPORT) HELLO payload not valid JSON`), o **`Invalid GLOBAL.TIMEZONE`** si **`GLOBAL.TIMEZONE`** no es un nombre IANA válido.
## Semántica del monitor en OpenBridge
- **`GROUP VOICE,INGRESS,RX`** — primera aparición de un flujo en una pata OpenBridge (depuración; visibilidad completa en logs).
@ -26,4 +43,4 @@ El panel muestra el estado **operativo** desde **START** (canónico); el **log d
## 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-mon.yaml`), 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`**, 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).