Итак, MVP моей ZigBee-поделки на ESP32 готов, и поделка введена в эксплуатацию. Потому, пришло время отчитаться.
Какова цель поделки?
Время близилось к весне, и жена попросила: "сделай мне подсветку для рассады".
В принципе, отрезать кусок диодной ленты, припаять к ней разъём для подключения блока питания, который вставить в розетку с таймером - дело на 10 минут. Но никакого дополнительного опыта эта задача мне не принесет, поэтому пришлось её дополнить дополнительными требованиями:
- регулировка яркости
- с датчиком температуры, влажности, давления (BME280)
- с влагозащитным датчиком температуры (DS18B20)
- с датчиком влажности почвы
- управление с инфракрасного пульта
- управлением и сбор данных с датчиков через систему Умного Дома по протоколу ZigBee
- управление через Telegram
- экспорт метрик с датчиков для последующего анализа в Grafana
- применимость поделки в иных задачах
У меня есть пару мест где еще нужно управлять диодной лентой, но нет необходимости во всех датчика. А так же где нет надобности управлять лентой, но нужны датчики.
У меня уже был опыт создания одного ZigBee прототипа на ESP32-C6-Devkit с двумя датчиками температуры DS18B20. На тот момент для меня было досадной неожиданностью то, что SDK ESP-IDF представляет C-интерфейс, и в коде моего проекты вышла смесь C и C++. С точки зрения эстетики и сопровождаемости - вышло так себе. И в данном проекте было решено отказаться от C++, и использовать только C.
Получилось как-то так...
- Устройство выступает в роли Router. Т.е. расширяет зону действия ZigBee сети.
- Управлять диодной лентой можно с ИК-пульта, ZigBee выключателя, из дашборда Zigbee2Mqtt, через Telegram бота, по расписанию системы умного дома, по модулю присутствия системы умного дома.
- Состояние (вкл/выкл) и яркость ленты сохраняется в NVRAM. Т.е. после восстановления питания - останется в том состоянии, которое было до отключения.
- ZigBee выключатель можно забиндить. Т.е. в случае недоступности координатора и самой системы Умного Дома - можно будет управлять напрямую. Правда, как показал эксперимент, после выключения координатора, выключатель может не работать (не находить прямой маршрут) в течение часа.
- Из Telegram бота можно посмотреть текущие данные датчиков, включить/выключить ленту, установить яркость, а так же установить режим, который не может быть переопределен с другого модуля управления (расписание, датчик присутствия и тп.)
- В расписании, помимо указания конкретного времени (и опционально даты), можно использовать синтаксис вроде "sunrise+10" или "sunset-10", которое устанавливает время в минутах относительно восхода/заката для текущего (или последующего) дня, для данных координат.
- К модулю присутствия может быть подключено несколько датчиков движения/присутствия. При обнаружении движения на любом датчике - лампа включается на определенное время с указанной яркостью. При "потере движения" одним из датчиков - ничего не происходит.
Если же напрямую завязать несколько датчиков движения к свету, то при "потере движения" на одном из датчиков - свет будет отключаться, что не удобно. - Один из кейсов использования следующий:
Включаем подсветку на полную яркость с 18:00 до 22:00.
В 22:00 активируется модуль присутствия, и при обнаружении движения, если подсветка не включена - будет её включать на 10 минут на минимальной яркости. Т.е. режим дополнительного ночника для ребенка, если ночью пойдет в туалет.
Что дальше?
- Смоделировать и заказать изготовление PCB-версии
- В первой PCB-версии буду использовать ESP32 Devkit, но в последующей хочу попробовать чисто модуль
- Сделать корпус
- Сделать клиентское ZigBee устройство (с кнопками, и возможно дисплеем), и попробовать групповой биндинг, и сцены.
Интересные моменты, которые всплыли в ходе реализации
- Важнейший документ для разработки ZigBee устройства: ZigBee Cluster Library Specification. Заказать его или другие полезные спецификации можно тут, или найти прямые ссылку в гугле.
- В упомянутой выше Cluster Library Specification описано огромное количество всевозможных кластеров. Однако, SDK ESP-IDF на данный момент поддерживает всего 40 стандартных кластеров. Актуальное количество можно грепнуть по CLUSTER_FN_ENTRY в файле czl.c. И судя по истории коммитов, разработчики не спешат их добавлять. И самому не добавишь - публичны только хидеры, а не исходники. 😢
И кастомный кластер, используя ID стандартного кластера, не создашь. Получаешь ошибку:
E (1609) ESP_ZIGBEE_CLUSTER: esp_zb_cluster_list_check(74): Custom cluster id is not within specified range! ESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG) at 0x4200df86
Т.е., ты покупаешь их модуль, а полноценное ZigBee устройство, соответсвующее спецификации, без ухищрений, используя их SDK сделать не можешь! 🤬
Так, например, SDK не поддерживает кластер Soil Moisture (влажность почвы). Так что, мне пришлось использовать кластер Humidity на отдельном эндпоинте. Для данного проекта вариант, конечно, работоспособный. Но совсем не эстетичный! - Одной из проблем было - невозможность произвести сопряжение с сетью, когда находишься в другой комнате от координатора. Что бы выполнить сопряжение, нужно было подойти на расстояние меньше метра к координатору. При этом в логе писало: "Network steering was not successful (status: ESP_FAIL)", и, если включить debug логирование, список отсканированных устройств типа роутер или координатор с уровнем их сигнала. Так вот, этот уровень сигнала зачастую был 0. Иногда прыгал до 20-30. А минимальный уровень, при котором ESP32 произведет сопряжение по умолчанию равен 32 (это значение можно получить вызовом
esp_zb_secur_network_min_join_lqi_get()
).
Я не знаю почему на этапе сопряжения, при сканировании, определяет такой низкий уровень сигнала. При этом, проблема воспроизводится на обоих моих устройствах, в разных сетях (квартира и деревня). Но проблема решается вызовомesp_zb_secur_network_min_join_lqi_set(0);
. После этого - сопряжение происходит моментально вдали от координатора.
Я пробовал восстанавливать Min Join LQI в 32, после сопряжения, но у меня есть подозрения, что он так же влияет на подключение конечных устройств к тебе, т.к. при установке значение в 0 - чаще видел подключенный выключатель прямо к своему устройству на карте сети.
Стек технологий проекта
- Разработка принципиальной схемы, ESP32-C6-Devkit, ZigBee, ESP-IDF, C++
- Довольно большим куском вышла доработка и рефакторинг своей ядра "умного дома": Golang, PostgreSQL
- Telegram Bot Api, Telegram WebApps, gRPC (обмен данными между Telegram ботом в облаке и "умным домом" в квартире), Prometheus, Grafana