fwt_software/docs/mqtt-api.md

4.3 KiB
Raw Permalink Blame History

MQTT API

The program is both an MQTT subscriber (remote control) and publisher (status + capture events). The MQTT channel is the MqttControlChannel implementation of IControlChannel (src/mqtt/MqttControlChannel.cpp, Eclipse Paho C++). It is used only when MQTT is enabled; otherwise a NullControlChannel runs (publishes dropped, auto-sweep mode). All topics are namespaced by tower name:

GGS/FWT/<tower_name>/...

<tower_name> comes from config.ini (General.tower_name). All messages use QoS 1. Published messages are retained.

Connection

  • Broker URI = Network.zkms_server_ip from config.ini; client ID = the tower name.
  • Auth: mqtt_user / mqtt_pw (preferring $FGC_MQTT_USER/$FGC_MQTT_PW); clean_session = true, keep-alive 20 s, set_automatic_reconnect(true).
  • Connect timeout 5 s. On connection loss Paho auto-reconnects; the channel re-subscribes on reconnect.
  • The program no longer exits if MQTT is unavailable — it logs a warning and continues in degraded mode. Use --no-mqtt to disable MQTT entirely (null channel).

Subscribed topics (inbound — remote control)

Subscribed on (re)connect; handled in MqttControlChannel::message_arrived() (src/mqtt/MqttControlChannel.cpp).

Topic Payload Parsed as Effect
GGS/FWT/<tower>/target_HDG integer heading as string, e.g. "137" validated with stoi, stored as string Sets the yaw target used in ControlCode 1 (converted to encoder counts via [Motor])
GGS/FWT/<tower>/ControlCode integer as string, "0" or "1" stoi → int Selects the capture mode (see below)

Invalid (non-integer) payloads are caught and logged; the previous value is kept.

The main loop consumes these via get_sub_data(), which returns a snapshot and clears the "available" flags so each update is acted on once (MqttControlChannel::poll()).

ControlCode semantics

ControlCode Behaviour (CaptureScheduler)
0 Automatic sweep. Walk the scan grid (ping-pong): MOVE to the next (yaw,pitch) waypoint, wait for standstill, trigger cameras.
1 Directed. MOVE yaw to target_HDG (pitch held), wait for standstill, trigger.

When a ControlCode message arrives, the program echoes the current code back on the StatusCode topic.

Published topics (outbound)

Topic When Payload QoS / Retain
GGS/FWT/<tower>/StatusCode At startup ("0"); whenever a ControlCode message is received (echoes the code) integer as string 1 / retained
GGS/FWT/<tower>/CamEvent After each image is saved JSON object (below) 1 / retained

CamEvent payload

Built by MqttControlChannel::publishCamEvent from a CamEvent:

{ "fwt":"Staeffelsberg", "cam":"RGB", "hdg":1373, "pit":300, "time":1719312345678 }
Field Type Meaning
fwt string Tower name (config.ini tower_name)
cam string Camera label: RGB, ACR, or NIR (by camera index)
hdg int Gimbal yaw heading × 10 (one decimal place encoded as integer) at capture time
pit int Gimbal pitch elevation × 10 at capture time (derived from the pitch encoder)
time int Capture timestamp, Unix epoch milliseconds (matches the .jxl filename)

The time value is the same Unix-ms timestamp used as the image filename, so a consumer can locate the file for a given event: <RGB|ACR|NIR>/<time>.jxl.

Topic summary

subscribe:  GGS/FWT/<tower>/target_HDG      (int heading)
            GGS/FWT/<tower>/ControlCode     (0 = auto sweep, 1 = directed)

publish:    GGS/FWT/<tower>/StatusCode      (echoed control code)
            GGS/FWT/<tower>/CamEvent        (JSON: fwt, cam, hdg×10, pit×10, time-ms)

Local testing

Point zkms_server_ip at a local broker and exercise the topics with Mosquitto:

mosquitto_sub -t 'GGS/FWT/Staeffelsberg/#' -v          # watch everything for the tower
mosquitto_pub -t 'GGS/FWT/Staeffelsberg/ControlCode' -m '0'
mosquitto_pub -t 'GGS/FWT/Staeffelsberg/target_HDG'  -m '180'