update: актуализация по анализу прошивки growbox-espidf

- MQTT.md: реальные имена полей (wEC, wpH, wLevel, Light, mcp/gpio)
- Добавлены топики OTA, status/full, status/actuators
- Полный список preferences с полями прошивки (60+ параметров)
- Актуальная схема status/sensors и status/mixer
- Pump ID расхождение задокументировано (сервер 1-8 vs прошивка 0-7)
- DEVICE_BEHAVIOR.md: FSM, exponential backoff, HA интеграция
This commit is contained in:
progl
2026-05-05 12:01:52 +03:00
parent 6655dd3d7a
commit e69665273c
2 changed files with 181 additions and 90 deletions
+67 -41
View File
@@ -5,35 +5,39 @@
```mermaid
stateDiagram-v2
[*] --> Booting: Включение питания
Booting --> WiFiConnect: Инициализация
Booting --> WiFiConnect: Инициализация периферии
WiFiConnect --> MQTTConnect: WiFi OK
WiFiConnect --> WiFiConnect: Retry (30s)
WiFiConnect --> WiFiConnect: Retry (exponential backoff)
MQTTConnect --> Connected: MQTT OK
MQTTConnect --> MQTTConnect: Retry (10s)
MQTTConnect --> MQTTConnect: Retry (exponential backoff)
Connected --> Publishing: Таймер сбора данных
Publishing --> Connected: Данные отправлены
Connected --> ExecutingCmd: Получена команда
Connected --> ExecutingCmd: Получена команда MQTT
ExecutingCmd --> Connected: Команда выполнена
Connected --> Disconnected: Потеря связи
Disconnected --> MQTTConnect: Reconnect
Connected --> OTA: Получена cmd/ota
OTA --> [*]: Перезагрузка после обновления
Connected --> [*]: Команда reboot / WDT reset
Connected --> Disconnected: Потеря связи
Disconnected --> MQTTConnect: Reconnect (exponential backoff)
Connected --> [*]: cmd/reboot или WDT reset
```
---
## Последовательность запуска
1. **Boot** — инициализация I2C, SPI, OneWire периферии
2. **WiFi** — подключение, получение IP
1. **Boot** — инициализация I2C, SPI, OneWire, MCP23017
2. **WiFi** — подключение, получение IP (exponential backoff при неудаче)
3. **MQTT connect** — handshake с брокером
4. **Publish `{UID}/status = "connected"`** — уведомление сервера
5. **Получить preferences** — сервер отвечает `{UID}/set/preferences/all`
6. **Применить калибровку** — записать коэффициенты в память
7. **Запуск основного цикла** — периодический сбор и публикация данных
4. **LWT настройка**`{UID}/availability = "offline"` при разрыве
5. **Publish `{UID}/status = "connected"`** — уведомление сервера
6. **Получить preferences** — сервер отвечает `{UID}/set/preferences/all`
7. **Применить калибровку** — записать коэффициенты в NVS/RAM без перезагрузки
8. **Запуск основного цикла** — периодический сбор и публикация данных
---
@@ -41,11 +45,13 @@ stateDiagram-v2
| Датчик | Интервал |
|--------|----------|
| pH, EC, Temp | ~10 сек |
| AirTemp, AirHum | ~30 сек |
| RSSI, uptime | ~60 сек |
| pH, EC, wNTC | ~10 сек |
| AirTemp, AirHum, AirPress | ~30 сек |
| RootTemp (DS18B20) | ~15 сек |
| RSSI, CPUTemp, FreeHeap, Vcc | ~60 сек |
| uptime | ~60 сек |
| MixerWeight | ~5 сек (если mixer_enabled) |
| readGPIO | при изменении |
| mcp/gpio | при изменении состояния |
---
@@ -58,44 +64,64 @@ stateDiagram-v2
2. `ESP.restart()`
### `cmd/gpio/{pin}`
1. Проверить pin ∈ [0, 15]
2. MCP23017 → setPin(pin, state)
- Проверить pin ∈ [0, 15], payload ∈ {"0", "1"}
- MCP23017 → setPin(pin, state)
### `set/pump/{id}/run`
1. Проверить id ∈ [1, 8], time ∈ [1, 60000]
2. Включить помпу
3. Запустить таймер
4. По истечении времени — выключить
- Проверить id ∈ [0, 7] ⚠️ (см. расхождение ниже), time ∈ [1, 60000]
- Включить помпу → таймер → выключить
### `set/pump/{id}/dispense`
1. Проверить id ∈ [1, 8], grams ∈ [0.1, 1000]
2. Рассчитать время через `ml/sec` калибровку помпы
3. Включить → таймер → выключить
4. Обновить счётчик `total_dispensed`
- Проверить id ∈ [0, 7] ⚠️, grams ∈ [0.1, 1000]
- Рассчитать время через ml/sec калибровку помпы
- Включить → таймер → выключить
- Обновить счётчик `total_dispensed`
### `cmd/pump/{id}/stop`
1. Немедленно выключить помпу
2. Сбросить таймер
- Проверить id ∈ [0, 7] ⚠️
- Немедленно выключить помпу, сбросить таймер
### `set/preferences/all`
1. Разобрать JSON
2. Обновить только пришедшие поля в NVS / RAM
3. Применить новые коэффициенты калибровки без перезагрузки
- Разобрать JSON, обновить только пришедшие поля в NVS / RAM
- Применить новые коэффициенты без перезагрузки
### `cmd/ota`
- Payload: пустой (использует `preferences.updateUrl`) или URL строка (override)
- Скачать и прошить firmware.bin
- Перезагрузиться
### `cmd/ota-storage`
- Аналогично `cmd/ota` но для LittleFS (`preferences.updateFsUrl`)
---
## ⚠️ Pump ID расхождение
| Сторона | Диапазон | Код |
|---------|----------|-----|
| Сервер (API serializer) | 18 | `min_value=1, max_value=8` |
| Прошивка (валидация) | 0–7 | `pumpId < 0 \|\| pumpId > 7` |
| Прошивка (итерация mixer) | 1pumpCount | `for pumpId = 1...pumpCount` |
**Следствие**: сервер отправляет `set/pump/8/run` → прошивка валидирует `8 > 7` → команда игнорируется.
**Рекомендация**: привести к единому стандарту 1-based (1–8). Исправить валидацию в `mqtt_callbacks.cpp` строки 457, 482, 507 на `pumpId < 1 || pumpId > 8`.
---
## Reconnect логика
- WiFi: авто-реконнект встроенный в ESP-IDF
- MQTT: переподключение каждые 10 секунд
- При восстановлении MQTT: снова публикует `{UID}/status = "connected"`
- Сервер снова отправляет preferences (идемпотентно)
- WiFi: встроенный авто-реконнект ESP-IDF
- MQTT: экспоненциальный backoff (1s → 2s → 4s → ... → max 60s)
- При восстановлении: публикует `{UID}/status = "connected"` → сервер снова шлёт preferences
---
## OTA обновления
## Home Assistant интеграция (отдельный канал)
URL прошивки: `preferences.updateUrl`
По умолчанию: `https://ponics.online/static/wegabox/esp32-local/firmware.bin`
Триггер обновления: команда (TBD) или автоматически при запуске если новая версия.
Прошивка поддерживает параллельную интеграцию с Home Assistant через MQTT.
Топики (не используются сервером ponics.online):
- `{UID}/availability` — online/offline
- `{UID}/pin/{i}/cmd` — управление GPIO
- `{UID}/pin/{i}/state` — состояние GPIO
- `{UID}/mixer/cmd` — управление миксером
- Autodiscovery топики для HA