# growbox (ESP32-контроллер) Прошивка для реального ESP32, обслуживающая зону "Гроубокс" платформы [home_automatization](../../home_automatization). Одна плата владеет четырьмя устройствами: `sensor-1` (DHT22) и три реле-актуатора — `light-1`, `pump-1`, `fan-1`. ## Протокол (MQTT, mosquitto из docker-compose платформы, порт 1883) - `devices/{device_id}/telemetry` — публикует контроллер, JSON `{"device_id","zone_id","sensor_type","value","timestamp"}`, timestamp — RFC3339 UTC. `sensor-1` шлёт по одному сообщению на `temperature` и `humidity` раз в `TELEMETRY_INTERVAL_MS`. - `devices/{device_id}/commands` — подписывается контроллер (wildcard `devices/+/commands`, фильтрует по своим 3 актуаторам), JSON `{"action":"turn_on"|"turn_off"|"set_level","level"?}`. - `devices/{device_id}/ack` — публикует контроллер после применения команды, JSON `{"state":{"power":"on"|"off","level"?}}`. Реального диммирования нет (обычные реле), поэтому `set_level` трактуется как порог: `level > 0` включает реле, `level <= 0` выключает. device_id в конфиге должны совпадать с `devices.external_id`, засеянными в Laravel (`DemoGrowboxSeeder` использует `sensor-1`/`fan-1`), а `zone_id` — с `zones.id` зоны "Гроубокс" в Postgres. ## Железо | Назначение | Пин (по умолчанию) | |-----------------|---------------------| | DHT22 data | GPIO4 | | Реле — light-1 | GPIO16 | | Реле — pump-1 | GPIO17 | | Реле — fan-1 | GPIO18 | Реле-модули по умолчанию считаются активными по LOW (`RELAY_ACTIVE_LOW` в `config.h`) — типично для дешёвых китайских модулей на оптопаре. Если ваши реле активны по HIGH — поменяйте флаг. DHT22 требует подтягивающий резистор ~10кОм между data и VCC, если он не встроен в конкретный модуль. ### Схема подключения ``` ESP32 DevKitC ┌───────────────────────┐ DHT22 DATA ───────┤ GPIO4 │ (+10к подтяжка │ │ DATA -> 3V3) │ │ │ │ Реле LIGHT IN ────┤ GPIO16 │ Реле PUMP IN ────┤ GPIO17 │ Реле FAN IN ────┤ GPIO18 │ │ │ 3V3 ────┤ 3V3 │ GND ────┤ GND │ USB/5V ─┤ VIN │ └───────────────────────┘ DHT22: VCC -> 3V3 GND -> GND DATA -> GPIO4 Реле-модуль: VCC -> 5V (VIN) или 3V3 (смотри маркировку модуля) GND -> GND (общий с ESP32) IN -> GPIO16 / GPIO17 / GPIO18 ⚠️ Реле коммутируют цепь самой нагрузки (свет/насос/вентилятор, обычно 12V/220V) через контакты COM/NO/NC — это ОТДЕЛЬНАЯ силовая цепь со своим источником питания, к GPIO ESP32 она не подключается. К плате идёт только сигнальный IN каждого реле-модуля. ``` ## Библиотеки Через Arduino Library Manager (Sketch → Include Library → Manage Libraries): - `PubSubClient` (Nick O'Leary) — MQTT-клиент - `ArduinoJson` (Benoit Blanchon, v7) — сериализация/парсинг JSON - `DHT sensor library` (Adafruit) + зависимость `Adafruit Unified Sensor` - Board support: `esp32` (Espressif Systems) через Boards Manager `WebServer` (веб-интерфейс) и `WiFi` идут в комплекте с board support `esp32` — отдельно ставить не нужно. ## Веб-интерфейс Каждая плата поднимает у себя простую страницу и JSON API на порту 80 — удобно наблюдать/управлять локально, не дожидаясь Laravel/MQTT: - `GET /` — HTML-страница: показания DHT22 + кнопки Вкл/Выкл для light-1/pump-1/fan-1. - `GET /api/state` — JSON `{"sensor":{"has_reading","temperature","humidity"},"devices":{"light-1":{"power"},...}}`. - `POST /api/command` — JSON-тело `{"device_id","action","level"?}`, тот же формат, что и в MQTT-команде. Команда с веб-UI применяется через тот же код и публикует тот же ack в `devices/{id}/ack`, что и команда из device-control-service — device shadow платформы (Redis) не расходится с реальным состоянием железа независимо от того, кто его переключил. Включается/выключается флагом `ENABLE_WEB_UI` в `config.h` (`1`/`0`) — при `0` HTTP-сервер не поднимается вообще, порт 80 не слушается. У сервера нет авторизации — только для локальной сети, как и mosquitto платформы; для выхода за пределы LAN сначала нужно добавить хотя бы Basic Auth. ## Настройка и прошивка через Arduino IDE 1. **Поддержка ESP32.** Arduino IDE → Settings → «Additional boards manager URLs» → добавить: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json` 2. **Ядро.** Tools → Board → Boards Manager → найти `esp32` → установить пакет `esp32 by Espressif Systems`. 3. **Библиотеки.** Tools → Manage Libraries → поставить по одной: `PubSubClient`, `ArduinoJson` (v7), `DHT sensor library` (IDE предложит доустановить зависимость `Adafruit Unified Sensor` — согласиться). 4. **Скетч.** File → Open → `controllers/growbox/growbox.ino` — остальные `.h`/`.cpp` подхватятся вкладками автоматически. 5. **Конфиг.** `cp config.h.example config.h`, заполнить Wi-Fi SSID/пароль, IP хоста с поднятым `docker compose` платформы (mosquitto слушает `0.0.0.0:1883` — доступен по IP машины в локальной сети), `zone_id` и `device_id`. Если IDE уже была открыта — переоткрыть скетч. 6. **Плата и порт.** Подключить ESP32 по USB (кабель именно с передачей данных). Tools → Board → esp32 → `ESP32 Dev Module` (или точная модель). Tools → Port → появившийся `/dev/cu.usbserial-*` / `/dev/cu.SLAB_USBtoUART`. 7. **Заливка.** Кнопка Upload. Часть плат просит зажать кнопку `BOOT` на плате до появления точек соединения в логе. 8. **Проверка.** Serial Monitor, 115200 бод — лог подключения к Wi-Fi/NTP/MQTT/веб-сервера, публикации телеметрии/команд и IP платы для похода в веб-интерфейс. **Если не заливается:** - порта нет в списке — нужен драйвер USB-UART моста платы (CP2102 обычно ставится сам на современной macOS, CH340 — вручную); - `Failed to connect to ESP32` / `No serial data received` — зажать `BOOT` на плате на время заливки; - заливка обрывается или очень долгая — Tools → Upload Speed → понизить с 921600 до 115200. ### Сборка через `arduino-cli` (если не через IDE) ```bash arduino-cli core install esp32:esp32 arduino-cli lib install "PubSubClient" "ArduinoJson" "DHT sensor library" arduino-cli compile --fqbn esp32:esp32:esp32 growbox arduino-cli upload --fqbn esp32:esp32:esp32 -p /dev/cu.usbserial-XXXX growbox ``` На macOS `arduino-cli` по умолчанию ставит библиотеки в `~/Documents/Arduino/libraries` — если этот каталог защищён sandbox'ом (Operation not permitted при установке библиотек, встречалось в среде этого агента), перенаправьте sketchbook в доступное место: `arduino-cli config set directories.user ~/путь/без/ограничений`. Через саму Arduino IDE (GUI-приложение) это обычно не требуется — она сама запрашивает нужные разрешения у macOS. ## Проверка end-to-end При работающем `docker compose` в `home_automatization` и засеянных Postgres-данных (зона + `sensor-1`/`light-1`/`pump-1`/`fan-1`): - телеметрия должна доходить до ClickHouse через ingest-service; - команда через Laravel UI (или напрямую через `grpcurl` в device-control-service) должна прийти на плату и вызвать щелчок реле, а затем ack — обновить `reported_state`/`last_seen` в Redis device shadow.