1a9c92b6db
Includes edge-node (FastAPI/MQTT/Discord voice), op25-container (SDR decoder), and icecast (audio streaming).
72 lines
2.5 KiB
Markdown
72 lines
2.5 KiB
Markdown
# DRB Client (Edge Node)
|
|
|
|
The client-side stack for the Discord Radio Bot system. Runs on the SDR hardware machine. Decodes radio with OP25, streams audio via Icecast, and connects to the C2 server over MQTT.
|
|
|
|
## Services
|
|
|
|
| Service | Description |
|
|
|---|---|
|
|
| `op25` | OP25 SDR decoder — tunes to radio systems and streams decoded audio |
|
|
| `icecast` | Audio streaming server — receives audio from OP25 and serves it over HTTP |
|
|
| `edge-node` | FastAPI node agent — bridges OP25 metadata, MQTT C2 commands, and Discord voice |
|
|
|
|
All services run with `network_mode: host` so they share the host network and can reach each other on localhost.
|
|
|
|
## Prerequisites
|
|
|
|
- Docker + Docker Compose
|
|
- An RTL-SDR or compatible SDR dongle connected to the host
|
|
- Network access to the DRB server (C2 server)
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
# 1. Copy env file
|
|
cp .env.example .env
|
|
|
|
# 2. Fill in .env
|
|
# At minimum: NODE_ID, MQTT_BROKER (IP of the C2 server)
|
|
|
|
# 3. Build and start
|
|
docker compose build
|
|
docker compose up -d
|
|
```
|
|
|
|
## Environment Variables (`.env`)
|
|
|
|
| Variable | Description | Default |
|
|
|---|---|---|
|
|
| `NODE_ID` | Unique identifier for this node | required |
|
|
| `NODE_NAME` | Human-readable name shown in the UI | `My Radio Node` |
|
|
| `NODE_LAT` / `NODE_LON` | GPS coordinates for the map view | `0.0` |
|
|
| `MQTT_BROKER` | IP or hostname of the C2 server | `localhost` |
|
|
| `MQTT_PORT` | MQTT broker port | `1883` |
|
|
| `C2_URL` | C2 server HTTP API URL (for audio uploads) | — |
|
|
| `ICECAST_HOST` | Icecast hostname (leave as localhost) | `localhost` |
|
|
| `ICECAST_PORT` | Icecast port | `8000` |
|
|
| `ICECAST_MOUNT` | Icecast mount point | `/radio` |
|
|
|
|
## Node Provisioning Flow
|
|
|
|
1. Start the client stack — the edge node connects to MQTT and sends a **checkin**
|
|
2. The C2 server registers the node as **pending approval**
|
|
3. An admin approves the node in the web UI
|
|
4. The admin assigns a **radio system** to the node via the UI
|
|
5. The C2 server pushes the system config over MQTT
|
|
6. The edge node writes the config and **starts OP25**
|
|
7. OP25 begins decoding and streaming audio to Icecast
|
|
|
|
After a restart, OP25 resumes automatically if the node was already configured.
|
|
|
|
## Discord Voice
|
|
|
|
When a user runs `/join` in Discord (or clicks "Join Discord" in the UI), the C2 server sends a `discord_join` command to this node over MQTT. The edge node spins up a Discord bot using a token from the server's token pool and connects it to the requested voice channel, streaming live audio from Icecast.
|
|
|
|
## Logs
|
|
|
|
```bash
|
|
docker compose logs -f edge-node
|
|
docker compose logs -f op25
|
|
docker compose logs -f icecast
|
|
```
|