89 lines
3.8 KiB
Markdown
89 lines
3.8 KiB
Markdown
# 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'
|
||
```
|