fwt_software/docs/mqtt-api.md

89 lines
3.8 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). It
uses the Eclipse Paho C++ async client ([MQTT.cpp](../MQTT.cpp)). 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` from config; `clean_session = true`, keep-alive 20 s.
- Connect timeout 5 s; on connection loss the client auto-reconnects (`reconnect()` with a 2.5 s backoff,
re-subscribing on success).
- **The program exits at startup if the initial connect fails** ([main.cpp](../main.cpp) lines 162-165).
## Subscribed topics (inbound — remote control)
Subscribed in `MQTTCallback::connected()` ([MQTT.cpp](../MQTT.cpp) lines 17-23). Handled in
`message_arrived()` ([MQTT.cpp](../MQTT.cpp) lines 25-54).
| 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 ([MQTT.h](../MQTT.h) lines 125-131).
### 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 in [Camera.cpp](../Camera.cpp) line 389:
```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'
```