fwt_software/docs/mqtt-api.md

93 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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](../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](../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 target heading used in ControlCode 1 (`kd<heading>`) |
| `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 ([main.cpp](../main.cpp) lines 293-334) |
|-------------|---------------------------------------------------|
| `0` | **Automatic sweep.** On each interval, send `p` to advance/stop the gimbal, then trigger cameras. |
| `1` | **Directed.** On each interval, send `kd<target_HDG>` to drive to the heading from `target_HDG`, then 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`:
```json
{ "fwt":"Staeffelsberg", "cam":"RGB", "hdg":1373, "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 heading **× 10** (one decimal place encoded as integer) at capture time |
| `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, time-ms)
```
## Local testing
Point `zkms_server_ip` at a local broker and exercise the topics with Mosquitto:
```bash
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'
```