6655dd3d7a
MQTT топики, REST API, поведение устройства, маппинг датчиков. Mermaid диаграммы: flow подключения, обработка сообщений, FSM устройства.
7.2 KiB
7.2 KiB
MQTT Protocol
Общее
- Брокер: Mosquitto 2.x (порт 1883)
- Topic prefix:
{UID}— UUID токен устройства (из БДGrowBox.token) - QoS: 1 для команд, 0 для данных датчиков
- Subscribe: сервер подписан на
#(все топики)
Flow: подключение устройства
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: команда с веб-интерфейса
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.
{
"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.
{
"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)
Устаревший формат, поддерживается для обратной совместимости. Новые устройства не используют.
{
"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 0–15) |
{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: 1–8, время: 1–60000 мс |
{UID}/set/pump/{id}/dispense |
"50.5" (граммы) |
id: 1–8, граммы: 0.1–1000 |
Настройки (set/preferences/all)
Полная конфигурация устройства. Отправляется при подключении или изменении настроек.
{
"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
}
Все поля опциональны — устройство применяет только те, что пришли.
Обработка сообщений на сервере
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 уведомление]