Files
ponics-protocol/MQTT.md
T
progl 6655dd3d7a init: спецификация протокола WegaBox ↔ ponics.online
MQTT топики, REST API, поведение устройства, маппинг датчиков.
Mermaid диаграммы: flow подключения, обработка сообщений, FSM устройства.
2026-05-05 11:42:57 +03:00

227 lines
7.2 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 Protocol
## Общее
- **Брокер**: Mosquitto 2.x (порт 1883)
- **Topic prefix**: `{UID}` — UUID токен устройства (из БД `GrowBox.token`)
- **QoS**: 1 для команд, 0 для данных датчиков
- **Subscribe**: сервер подписан на `#` (все топики)
---
## Flow: подключение устройства
```mermaid
sequenceDiagram
participant ESP32 as WegaBox (ESP32)
participant MQTT as MQTT Broker
participant Django as ponics.online (Django)
participant Redis
ESP32->>MQTT: publish {UID}/status = "connected"
MQTT->>Django: forward
Django->>Django: push_box_settings(box)
Django->>MQTT: publish {UID}/set/preferences/all = {JSON}
MQTT->>ESP32: apply calibration & config
loop Каждые N секунд
ESP32->>MQTT: publish {UID}/data-timescale/EC = "1.85"
ESP32->>MQTT: publish {UID}/data-timescale/ph = "6.2"
ESP32->>MQTT: publish {UID}/data-timescale/wNTC = "22.5"
MQTT->>Django: forward
Django->>Redis: update live cache (boxconfig-{token})
Django->>Django: batch → TimescaleDB (каждые 25с или 100 метрик)
end
```
---
## Flow: команда с веб-интерфейса
```mermaid
sequenceDiagram
participant User as Браузер
participant Django as ponics.online (Django)
participant MQTT as MQTT Broker
participant ESP32 as WegaBox (ESP32)
User->>Django: POST /api/box/{id}/pump/run/ {pump_id:1, time_ms:5000}
Django->>MQTT: publish {UID}/set/pump/1/run = "5000"
MQTT->>ESP32: execute pump 1 for 5000ms
Django->>User: 200 {"success": true}
Note over ESP32: Команды fire-and-forget, ответа нет
```
---
## Топики: устройство → сервер (Subscribe)
### `{UID}/data-timescale/{METRIC_NAME}`
Основной поток данных датчиков. Каждый датчик — отдельное сообщение.
**Payload**: строка с числом (например `"6.24"`, `"1.85"`, `"22.5"`)
```
{UID}/data-timescale/EC → значение EC (мСм/см)
{UID}/data-timescale/ph → значение pH
{UID}/data-timescale/wNTC → температура воды (°C, откалиброванная)
{UID}/data-timescale/AirTemp → температура воздуха (°C)
{UID}/data-timescale/AirHum → влажность воздуха (%)
{UID}/data-timescale/AirPress → давление (гПа)
{UID}/data-timescale/RootTemp → температура субстрата/корней (°C, DS18B20)
{UID}/data-timescale/calc_dist → уровень воды (см/%)
{UID}/data-timescale/calc_pr → освещённость (%)
{UID}/data-timescale/RSSI → уровень WiFi сигнала (dBm)
{UID}/data-timescale/uptime → аптайм устройства (мс)
{UID}/data-timescale/MixerWeight → вес миксера (г)
{UID}/data-timescale/readGPIO → битовая маска GPIO MCP23017 (0-65535)
```
### `{UID}/status`
Payload: строка `"connected"` — устройство подключилось к брокеру.
Триггер: сервер отправляет настройки (`set/preferences/all`).
### `{UID}/status/sensors`
Ответ на запрос `{UID}/cmd/status/sensors`.
```json
{
"ph": 6.24,
"ec": 1.85,
"temp_cal": 22.5,
"calc_dist": 45.2,
"airTemp": 24.1,
"airHumidity": 65.0,
"RSSI": -65,
"uptime": 3600000
}
```
### `{UID}/status/mixer`
Ответ на запрос `{UID}/cmd/status/mixer`.
```json
{
"pumps": [
{"index": 0, "name": "CaNO3", "total_dispensed": 480.5},
{"index": 1, "name": "KNO3", "total_dispensed": 320.0},
{"index": 2, "name": "MgSO4", "total_dispensed": 150.0}
]
}
```
### `{UID}/main` (legacy)
Устаревший формат, поддерживается для обратной совместимости. Новые устройства не используют.
```json
{
"sensors": {
"ph": "6.5",
"ec": "1.8",
"temp_cal": "22.5"
},
"system": {
"uptime": "3600000",
"RSSI": "-65"
}
}
```
---
## Топики: сервер → устройство (Publish)
### Команды (`cmd/`)
| Топик | Payload | Описание |
|-------|---------|----------|
| `{UID}/cmd/reboot` | `"1"` | Перезагрузка устройства |
| `{UID}/cmd/gpio/{pin}` | `"1"` / `"0"` | GPIO HIGH/LOW (MCP23017, pin 015) |
| `{UID}/cmd/pump/{id}/stop` | `"1"` | Стоп помпы (id 1–8) |
| `{UID}/cmd/status` | `"1"` | Запрос полного статуса |
| `{UID}/cmd/status/sensors` | `"1"` | Запрос данных датчиков |
| `{UID}/cmd/status/actuators` | `"1"` | Запрос статуса актуаторов |
| `{UID}/cmd/status/mixer` | `"1"` | Запрос статуса миксера |
### Управление помпами (`set/pump/`)
| Топик | Payload | Ограничения |
|-------|---------|------------|
| `{UID}/set/pump/{id}/run` | `"5000"` (мс) | id: 18, время: 160000 мс |
| `{UID}/set/pump/{id}/dispense` | `"50.5"` (граммы) | id: 18, граммы: 0.11000 |
### Настройки (`set/preferences/all`)
Полная конфигурация устройства. Отправляется при подключении или изменении настроек.
```json
{
"ntcDAC": 4095,
"ntcB": 3950,
"ntcValKorr": 0.0,
"ntcType": "NTC3950",
"R1": 10000,
"Rx1": 1000,
"Rx2": 1000,
"Dr": 1.0,
"ec1": 1.41,
"ec2": 12.88,
"ex1": 0.5,
"ex2": 0.9,
"kt": 0.019,
"ecKorr": 1.0,
"px1": 100,
"px2": 580,
"px3": 1023,
"py1": 0.0,
"py2": 7.0,
"py3": 14.0,
"pHlKorr": 0.0,
"maxLLevel": 30.0,
"maxLRaw": 100,
"minLLevel": 10.0,
"minLRaw": 500,
"hostname": "wega-box-1",
"updateUrl": "https://ponics.online/static/wegabox/esp32-local/firmware.bin",
"ds18b20_enabled": true,
"bme280_enabled": true,
"ec_enabled": true,
"mixer_enabled": false,
"mixer_pumpCount": 8,
"hx711_calibrationA": 1000.0,
"hx711_calibrationB": 500.0,
"ecDoser_enabled": false,
"ecDoser_intervalSec": 3600,
"ecDoser_limitEC": 3.0
}
```
**Все поля опциональны** — устройство применяет только те, что пришли.
---
## Обработка сообщений на сервере
```mermaid
flowchart TD
MSG[MQTT сообщение] --> CHECK{Суффикс топика}
CHECK -->|"main"| REDIS[Redis hash-store]
CHECK -->|"status/mixer"| MIXER[Обновить статус миксера]
CHECK -->|"status/sensors"| SENS[Обновить кеш датчиков]
CHECK -->|"status" + "connected"| SYNC[push_box_settings → отправить преференции]
CHECK -->|"data-timescale/{METRIC}"| PROC[MessageProcessor]
PROC --> PARSE[Парсинг значения]
PARSE --> MAP[Маппинг имени поля]
MAP --> BATCH[Batcher<br/>100 метрик / 25 сек]
BATCH --> TSDB[(TimescaleDB)]
MAP --> CACHE[Redis live cache<br/>boxconfig-{token}]
CACHE --> COND{Проверка условий}
COND -->|Сработало| TG[Telegram уведомление]
```