# Device Behavior ## Конечный автомат устройства ```mermaid stateDiagram-v2 [*] --> Booting: Включение питания Booting --> WiFiConnect: Инициализация периферии WiFiConnect --> MQTTConnect: WiFi OK WiFiConnect --> WiFiConnect: Retry (exponential backoff) MQTTConnect --> Connected: MQTT OK MQTTConnect --> MQTTConnect: Retry (exponential backoff) Connected --> Publishing: Таймер сбора данных Publishing --> Connected: Данные отправлены Connected --> ExecutingCmd: Получена команда MQTT ExecutingCmd --> Connected: Команда выполнена Connected --> OTA: Получена cmd/ota OTA --> [*]: Перезагрузка после обновления Connected --> Disconnected: Потеря связи Disconnected --> MQTTConnect: Reconnect (exponential backoff) Connected --> [*]: cmd/reboot или WDT reset ``` --- ## Последовательность запуска 1. **Boot** — инициализация I2C, SPI, OneWire, MCP23017 2. **WiFi** — подключение, получение IP (exponential backoff при неудаче) 3. **MQTT connect** — handshake с брокером 4. **LWT настройка** — `{UID}/availability = "offline"` при разрыве 5. **Publish `{UID}/status = "connected"`** — уведомление сервера 6. **Получить preferences** — сервер отвечает `{UID}/set/preferences/all` 7. **Применить калибровку** — записать коэффициенты в NVS/RAM без перезагрузки 8. **Запуск основного цикла** — периодический сбор и публикация данных --- ## Периодичность публикации данных | Датчик | Интервал | |--------|----------| | pH, EC, wNTC | ~10 сек | | AirTemp, AirHum, AirPress | ~30 сек | | RootTemp (DS18B20) | ~15 сек | | RSSI, CPUTemp, FreeHeap, Vcc | ~60 сек | | uptime | ~60 сек | | MixerWeight | ~5 сек (если mixer_enabled) | | mcp/gpio | при изменении состояния | --- ## Обработка команд Все команды **fire-and-forget** — ответ не отправляется. ### `cmd/reboot` 1. Завершить активные операции помп (стоп) 2. `ESP.restart()` ### `cmd/gpio/{pin}` - Проверить pin ∈ [0, 15], payload ∈ {"0", "1"} - MCP23017 → setPin(pin, state) ### `set/pump/{id}/run` - Проверить id ∈ [1, 8], time ∈ [1, 60000] - Включить помпу → таймер → выключить ### `set/pump/{id}/dispense` - Проверить id ∈ [1, 8], grams ∈ [0.1, 1000] - Рассчитать время через ml/sec калибровку помпы - Включить → таймер → выключить - Обновить счётчик `total_dispensed` ### `cmd/pump/{id}/stop` - Проверить id ∈ [1, 8] - Немедленно выключить помпу, сбросить таймер ### `set/preferences/all` - Разобрать JSON, обновить только пришедшие поля в NVS / RAM - Применить новые коэффициенты без перезагрузки ### `cmd/ota` - Payload: пустой (использует `preferences.updateUrl`) или URL строка (override) - Скачать и прошить firmware.bin - Перезагрузиться ### `cmd/ota-storage` - Аналогично `cmd/ota` но для LittleFS (`preferences.updateFsUrl`) --- ## Pump ID: единый стандарт 1–8 Сервер и прошивка используют 1-based индексацию (1–8). Исправлено в прошивке: commit `aa5db288` — валидация `0-7` → `1-8` в `mqtt_callbacks.cpp`. --- ## Reconnect логика - WiFi: встроенный авто-реконнект ESP-IDF - MQTT: экспоненциальный backoff (1s → 2s → 4s → ... → max 60s) - При восстановлении: публикует `{UID}/status = "connected"` → сервер снова шлёт preferences > **Важно**: Публикация `status = "connected"` должна происходить в колбэке подключения MQTT, > а не только при первом старте. Иначе после реконнекта устройство не получит настройки с сервера. --- ## Типичные ошибки реализации ### 1. Неверный payload в `{UID}/status` ``` ❌ "online", "Online", "connected\n", "1" ✅ "connected" ``` Сервер проверяет точное совпадение байт. Неверный payload → `push_box_settings` не вызывается → устройство работает без калибровок из БД до следующей перезагрузки. ### 2. `status` публикуется только при первом старте При реконнекте MQTT (после обрыва WiFi, перезапуска брокера) нужно снова опубликовать `{UID}/status = "connected"`. Иначе после восстановления связи настройки не придут. ### 3. Pump ID отсчёт API использует 1-based индексацию (1–8). Прошивка внутренне хранит 0-based, но MQTT-команды и HTTP API принимают 1-based. Проверять валидацию: `id ∈ [1, 8]`. ### 4. HTTP API требует `Accept: application/json` При обращении к ponics.online API без этого заголовка сервер может вернуть 302 (редирект на страницу логина) вместо JSON. Клиенты должны явно указывать `Accept: application/json`. --- ## Home Assistant интеграция (отдельный канал) Прошивка поддерживает параллельную интеграцию с Home Assistant через MQTT. Топики (не используются сервером ponics.online): - `{UID}/availability` — online/offline - `{UID}/pin/{i}/cmd` — управление GPIO - `{UID}/pin/{i}/state` — состояние GPIO - `{UID}/mixer/cmd` — управление миксером - Autodiscovery топики для HA