# MQTT Support for DStarRepeater DStarRepeater can optionally publish log messages and repeater status to an MQTT broker, providing the same kind of live telemetry that MMDVMHost offers. This makes it possible to monitor D-Star repeater activity from dashboards, home-automation systems, or any MQTT client. **MQTT support is entirely optional.** When built without the MQTT flag the compiled binary is identical to the tree before MQTT was added — no MQTT code is included and no additional libraries are required. ## Building ### Without MQTT (default) ``` make ``` Produces the same `dstarrepeaterd` as the original codebase. No `libmosquitto` dependency. ### With MQTT Install `libmosquitto-dev` first: ``` sudo apt-get install libmosquitto-dev ``` Then build with the `MQTT` flag: ``` make MQTT=1 ``` This adds `-DMQTT` to the compiler flags and links against `-lmosquitto`. All MQTT code paths are guarded by `#if defined(MQTT)` / `#endif`, so the flag acts as a clean on/off switch. ## Configuration Add the following keys to your `dstarrepeater` configuration file (the same flat key=value format used by all other settings): ``` mqttHost=127.0.0.1 mqttPort=1883 mqttAuth=0 mqttUsername= mqttPassword= mqttKeepalive=60 mqttName=dstar-repeater ``` | Key | Default | Description | |-----------------|-------------------|----------------------------------------------------| | `mqttHost` | `127.0.0.1` | MQTT broker hostname or IP address | | `mqttPort` | `1883` | MQTT broker port | | `mqttAuth` | `0` | Enable authentication (`0` = off, `1` = on) | | `mqttUsername` | *(empty)* | Username when `mqttAuth=1` | | `mqttPassword` | *(empty)* | Password when `mqttAuth=1` | | `mqttKeepalive` | `60` | Keepalive interval in seconds | | `mqttName` | `dstar-repeater` | Client name; also used as the MQTT topic prefix | If `mqttHost` is left empty, MQTT is disabled at runtime even when compiled in. ## MQTT Topics All topics are automatically prefixed with the value of `mqttName`. For example, with the default name `dstar-repeater`: ### `dstar-repeater/log` Timestamped log messages, filtered by severity. The format matches the log file output: ``` M: 2025-03-08 14:22:01: Starting D-Star Repeater - 20180403 M: 2025-03-08 14:22:01: Using wxWidgets 3.0.5 on Linux 6.1.21-v8+ M: 2025-03-08 14:22:01: Callsign set to "GB7XX B", gateway set to "GB7XX G" M: 2025-03-08 14:22:01: Modem type set to "MMDVM" I: 2025-03-08 14:22:01: MQTT connected to 127.0.0.1:1883 as dstar-repeater M: 2025-03-08 14:22:01: Starting the D-Star repeater thread M: 2025-03-08 14:22:01: Poll text set to "linux_mmdvm-20180403" ``` Log levels (highest to lowest): | Letter | Level | Numeric | |--------|---------------|---------| | `F` | Fatal | 6 | | `E` | Error | 5 | | `W` | Warning | 4 | | `I` | Info | 3 | | `M` | Message | 2 | | `D` | Debug | 1 | Only messages at or above the configured threshold are published. The default threshold is **2** (Message level), matching MMDVMHost behaviour. ### `dstar-repeater/status` A JSON object published once per second with the current repeater state. This is the D-Star equivalent of MMDVMHost's status output: **Idle (no traffic):** ```json { "myCall1": "", "myCall2": "", "yourCall": "", "rptCall1": "", "rptCall2": "", "tx": false, "rxState": "listening", "rptState": "listening", "ber": 0.0, "text": "", "status1": "", "status2": "", "status3": "", "status4": "", "status5": "" } ``` **During an RF transmission:** ```json { "myCall1": "MW0MWZ ", "myCall2": " ", "yourCall": "CQCQCQ ", "rptCall1": "GB7XX B", "rptCall2": "GB7XX G", "tx": true, "rxState": "process_data", "rptState": "valid", "ber": 1.3, "text": "Hello from Pi-Star", "status1": "", "status2": "", "status3": "", "status4": "", "status5": "" } ``` **During a network (gateway) transmission:** ```json { "myCall1": "G4KLX ", "myCall2": " ", "yourCall": "GB7XX B", "rptCall1": "GB7XX B", "rptCall2": "GB7XX G", "tx": true, "rxState": "listening", "rptState": "network", "ber": 0.0, "text": "", "status1": "", "status2": "", "status3": "", "status4": "", "status5": "" } ``` #### Status Field Reference | Field | Type | Description | |------------|---------|-----------------------------------------------------------| | `myCall1` | string | Transmitting station's callsign (8 chars, space-padded) | | `myCall2` | string | Transmitting station's short suffix (4 chars) | | `yourCall` | string | Destination callsign (`CQCQCQ` for CQ calls) | | `rptCall1` | string | Repeater callsign with module letter | | `rptCall2` | string | Gateway callsign | | `tx` | boolean | `true` when the repeater is transmitting | | `rxState` | string | `listening`, `process_data`, or `process_slow_data` | | `rptState` | string | See repeater states below | | `ber` | float | Bit Error Rate as a percentage (0.0 when idle) | | `text` | string | Slow-data text message (if any) | | `status1`–`status5` | string | User-configured status text messages | #### Repeater States (`rptState`) | Value | Meaning | |----------------|------------------------------------------------------| | `listening` | Idle, waiting for traffic | | `valid` | Receiving valid RF traffic | | `valid_wait` | Valid RF transmission ended, waiting for ack window | | `invalid` | Receiving RF traffic that failed validation | | `invalid_wait` | Invalid RF ended, waiting | | `timeout` | Transmission timed out | | `timeout_wait` | Timeout ended, waiting | | `network` | Receiving traffic from the gateway/network | | `shutdown` | Repeater is shut down | ### `dstar-repeater/json` Event-driven JSON messages published at D-Star state transitions, in the format expected by [Display-Driver](https://github.com/MW0MWZ/Display-Driver). This means DStarRepeater can drive an OLED/TFT display via MQTT with no modifications to Display-Driver. Unlike the `status` topic (polled once per second), the `json` topic only publishes when something actually changes — a transmission starts, ends, or is lost. **RF transmission starts:** ```json {"D-Star":{"action":"start","source_cs":"MW0MWZ ","source_ext":" ","destination_cs":"CQCQCQ ","reflector":"GB7XX G","source":"rf"}} ``` **Network transmission starts:** ```json {"D-Star":{"action":"start","source_cs":"G4KLX ","source_ext":" ","destination_cs":"GB7XX B","reflector":"GB7XX G","source":"net"}} ``` **Transmission ends normally:** ```json {"D-Star":{"action":"end"}} ``` **Transmission lost (watchdog timeout):** ```json {"D-Star":{"action":"lost"}} ``` **Return to idle (sent after every end/lost):** ```json {"MMDVM":{"mode":"idle"}} ``` **BER update (published once per second during active RF):** ```json {"BER":{"mode":"D-Star","value":1.3}} ``` #### Display-Driver Compatibility These messages use the exact same JSON keys and structure that Display-Driver expects. If your `mqttName` is set to `dstar-repeater`, configure Display-Driver to subscribe to `dstar-repeater/json`. Display-Driver dispatches each top-level key to a specific parser: | Top-level key | Display-Driver parser | When published | |---------------|----------------------|------------------------------------------| | `D-Star` | `parseDStar()` | Transmission start, end, or lost | | `BER` | `parseBER()` | Once per second during active RF | | `MMDVM` | `parseMMDVM()` | On return to idle | ## Subscribing to MQTT Output Use any MQTT client to subscribe. For example, with `mosquitto_sub`: ```bash # Follow all DStarRepeater topics: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/#" # Log messages only: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/log" # Status JSON only: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/status" # Display-Driver-compatible events: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/json" # Pretty-print status with jq: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/status" | jq . # Pretty-print Display-Driver events with jq: mosquitto_sub -h 127.0.0.1 -t "dstar-repeater/json" | jq . ``` ## Comparison with MMDVMHost This implementation follows the same conventions as MMDVMHost's MQTT support: - Same `CMQTTConnection` class wrapping `libmosquitto` - Same topic-prefix convention (`{name}/topic`) - Same log-level filtering and format - Same PID-based client ID scheme (avoids the `time_t` truncation issue on 32-bit ARM) - Same configuration key names (`mqttHost`, `mqttPort`, etc.) - Same QoS default (EXACTLY_ONCE / QoS 2) The key difference is that DStarRepeater is a **publish-only** client — it does not subscribe to any MQTT topics or accept remote commands via MQTT. The configuration file format also differs: DStarRepeater uses flat `key=value` pairs rather than MMDVMHost's INI-style `[MQTT]` section. ## Troubleshooting **"Unable to start MQTT connection"** in logs: - Check that Mosquitto (or another MQTT broker) is running on the configured host and port - Verify credentials if `mqttAuth=1` - Check firewall rules if connecting to a remote broker **No messages appearing:** - Confirm the binary was built with `make MQTT=1` - Check that `mqttHost` is not empty in the config file - Verify the broker is accessible: `mosquitto_pub -h 127.0.0.1 -t test -m hello` **Log messages missing but status works:** - The log level threshold may be filtering them out. Lower-priority messages (Debug, Trace) are not published by default.