10 KiB
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):
{
"myCall1": "",
"myCall2": "",
"yourCall": "",
"rptCall1": "",
"rptCall2": "",
"tx": false,
"rxState": "listening",
"rptState": "listening",
"ber": 0.0,
"text": "",
"status1": "",
"status2": "",
"status3": "",
"status4": "",
"status5": ""
}
During an RF transmission:
{
"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:
{
"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. 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:
{"D-Star":{"action":"start","source_cs":"MW0MWZ ","source_ext":" ","destination_cs":"CQCQCQ ","reflector":"GB7XX G","source":"rf"}}
Network transmission starts:
{"D-Star":{"action":"start","source_cs":"G4KLX ","source_ext":" ","destination_cs":"GB7XX B","reflector":"GB7XX G","source":"net"}}
Transmission ends normally:
{"D-Star":{"action":"end"}}
Transmission lost (watchdog timeout):
{"D-Star":{"action":"lost"}}
Return to idle (sent after every end/lost):
{"MMDVM":{"mode":"idle"}}
BER update (published once per second during active RF):
{"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:
# 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
CMQTTConnectionclass wrappinglibmosquitto - Same topic-prefix convention (
{name}/topic) - Same log-level filtering and format
- Same PID-based client ID scheme (avoids the
time_ttruncation 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
mqttHostis 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.