Многие, кто пробовал разрабатывать собственные Zigbee-устройства, знакомы с отличной прошивкой PTVO. Это удобное решение, позволяющее быстро запустить простое устройство без глубоких знаний в программировании. Однако у такого подхода есть и свои ограничения — например, зависимость от стороннего ПО, невозможность гибкой настройки логики работы, а также закрытый исходный код. Для меня написание прошивки под микроконтроллеры Texas Instruments, такие как CC2530, оказалось достаточно сложной задачей. Кроме того, эти контроллеры требуют специфических инструментов для прошивки и отладки. А что если создать своё полноценное Zigbee-устройство с нуля — без ограничений, с открытым кодом и возможностью полной кастомизации? Да ещё и с использованием современных микроконтроллеров? Если вам это интересно, тогда приступим! Мы выберем PlatformIO — современную, кроссплатформенную среду разработки, которая отлично интегрируется с ESP-IDF, предоставляет богатый функционал, упрощает процесс сборки, прошивки и отладки. Совсем недавно компания Espressif представила новые микроконтроллеры — ESP32-C6 и ESP32-H2, которые, помимо привычного Wi-Fi и Bluetooth (в некоторых моделях), поддерживают и Zigbee/Thread. Это делает их отличным выбором для современных IoT-проектов. В моем примере используется компактная плата ESP32-C6 Super Mini. Это удобный вариант для прототипирования, с минимальным набором обвязки, но с полноценной поддержкой Zigbee. В качестве примера реализована простая функция переключения трёх реле. Вместо физических реле в демонстрационном коде изменяется цвет встроенного адресного светодиода WS2812, что позволяет удобно отлаживать логику работы даже без внешнего оборудования. При необходимости вы легко можете адаптировать код под реальные реле, заменив управление светодиодом на стандартную функцию digitalWrite() с выводами, к которым подключены реле.
В качестве ide для нашего проекта я буду использовать Platformio в среде разработки Visual Code Studio. Официально Platformio пока не перешли на Arduino core версии > 3 в котором реализована поддержка zigbee и новых микроконтроллеров. Поддержка есть в pioarduino ide Создайте новый проект и отредактируйте platformio.ini
[env:esp32-c6-devkitc-1] platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip board = esp32-c6-devkitc-1 monitor_speed = 115200 framework = arduino board_build.partitions = partitions.csv board_build.filesystem = spiffs build_flags = -D CORE_DEBUG_LEVEL=3 -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 -D ZIGBEE_MODE_ZCZR lib_deps = adafruit/Adafruit NeoPixel@^1.12.3
Обратите внимание на следующие обязательные параметры:
board_build.partitions = partitions.csv
Задает таблицу разделов памяти. В файле partitions.csv описаны такие разделы как: nvs, spiffs, factory, zb_nvs и т.д. Это критично для Zigbee (где нужен отдельный раздел под NVS Zigbee) и для работы файловой системы SPIFFS. Содержание файла partitions.csv:
# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x140000, app1, app, ota_1, 0x150000,0x140000, spiffs, data, spiffs, 0x290000,0x15B000, zb_storage, data, fat, 0x3EB000,0x4000, zb_fct, data, fat, 0x3EF000,0x1000, coredump, data, coredump,0x3F0000,0x10000,
Флаги:
CORE_DEBUG_LEVEL=3
- уровень логирования (3 = Info). Позволяет видеть больше отладочной информации в консоли.
ARDUINO_USB_MODE=1
- включает USB-режим (если поддерживается чипом).
ARDUINO_USB_CDC_ON_BOOT=1
- активирует CDC (виртуальный COM-порт) при загрузке.
ZIGBEE_MODE_ZCZR
- означает Zigbee Coordinator/Router режим
Скачайте архив с исходным кодом из репозитория github. Откройте проект в Platformio. Давайте пройдемся по самым необходимым настройкам программы, что бы вы смогли модифицировать код под свою задачу. Откройте файл в папке проекта Zigbee/zigbee.h.
#define MANUFACTURER_NAME "\x0B" "lukjanow.ru" #define MODEL_IDENTIFIER "\x0D" "Zigbee_Switch"
- Обязательные параметры для любого zigbee устройства в сети которые отображают производителя и идентификатор устройства. Они также нам понадобятся для добавления устройства в Home Assistan.
В файле Zigbee/zigbee.cpp найдите функцию createEndpoint() Здесь создаются три конечных устройства (endpoint), каждое из которых представляет выключатель (On/Off Switch).
esp_zb_endpoint_config_t endpoint_config = { .endpoint = endpoint_id, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID, .app_device_version = 1 };
-
endpoint
: номер endpoint’а, например 1. -
app_profile_id
: профиль Home Automation (HA) — стандартный Zigbee профиль. -
app_device_id
: тип устройства — выключатель. -
app_device_version
: версия устройства (можно оставить 1).
Добавление второго и третьего выключателей осуществляется через блоки которые повторяют аналогичную логику, но изменяют номер endpoint (endpoint_id + 1, endpoint_id + 2) и создают свои собственные списки кластеров, вручную добавляют кластер On/Off:
endpoint_config.endpoint = endpoint_id + 1; endpoint_config.app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID; esp_zb_cluster_list_t *switch2_cluster_list = createBasicClusters(); esp_zb_on_off_cluster_cfg_t switch2_cfg = { .on_off = false }; esp_zb_attribute_list_t *switch2_cluster = esp_zb_on_off_cluster_create(&switch2_cfg); esp_zb_cluster_list_add_on_off_cluster(switch2_cluster_list, switch2_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); esp_zb_ep_list_add_ep(ep_list, switch2_cluster_list, endpoint_config);
Давайте перейдем к главному файлу программы main.cpp Код приведенный ниже реализует обработчик обновления атрибутов Zigbee-кластера — функцию, которая вызывается Zigbee-стеком при получении нового значения атрибута от координатора (например, Home Assistant, Zigbee2MQTT и т.п.).
esp_err_t onAttributeUpdated(const esp_zb_zcl_set_attr_value_message_t *message){ esp_err_t ret = ESP_OK; if (!message) { log_i("Empry message"); return ESP_FAIL; } bool switchState = *(bool *)(message->attribute.data.value); if (message->info.dst_endpoint == HA_ESP_SENSOR_ENDPOINT){ log_i("Switch 1: %s", switchState ? "on" : "off"); //switchState ? DigitalWrite(pin1, 1) : DigitalWrite(pin1, 0); switchState ? setLedColor(255, 0, 0) : clearLed(); } else if (message->info.dst_endpoint == HA_ESP_SENSOR_ENDPOINT + 1){ log_i("Switch 2: %s", switchState ? "on" : "off"); //switchState ? DigitalWrite(pin2, 1) : DigitalWrite(pin2, 0); switchState ? setLedColor(0, 255, 0) : clearLed(); } else if (message->info.dst_endpoint == HA_ESP_SENSOR_ENDPOINT + 2){ log_i("Switch 3: %s", switchState ? "on" : "off"); //switchState ? DigitalWrite(pin3, 1) : DigitalWrite(pin3, 0); switchState ? setLedColor(0, 0, 255) : clearLed(); } return ret; }
- Функция вызывается, когда Zigbee координатор отправляет команду изменить значение какого-либо атрибута Zigbee-кластера на этом устройстве.
if (message->info.dst_endpoint == HA_ESP_SENSOR_ENDPOINT)
- Проверяется, на какой endpoint (конечную точку Zigbee) пришло сообщение.
HA_ESP_SENSOR_ENDPOINT
— базовое значение (1), к которому прибавляется+1
,+2
для остальных каналов.
switchState ? setLedColor(255, 0, 0) : clearLed();
- В зависимости от endpoint’а вызывается управление светодиодом. 1: красный, 2: зеленый, 3: синий.
//switchState ? DigitalWrite(pin1, 1) : DigitalWrite(pin1, 0);
- Это строка оставлена на будущее, если ты захочешь управлять реальными реле через GPIO, а не светодиодом.
После того как вы скомпилировали проект, загрузите прошивку в ESP32-C6 с помощью PlatformIO или любого другого удобного вам инструмента. По завершении прошивки и перезагрузке устройство автоматически перейдёт в режим сопряжения (pairing mode) и будет готово к подключению к Zigbee-сети. В качестве примера я покажу, как подключить наше новое устройство к Home Assistant с использованием HOMEd — программного шлюза, разработанного отечественными энтузиастами. Что такое HOMEd? HOMEd ZigBee — это программный мост (bridge) между Zigbee-сетью и MQTT-брокером, который позволяет интегрировать Zigbee-устройства разных производителей в Home Assistant без необходимости использовать фирменные шлюзы и приложения (такие как Tuya, Xiaomi, Aqara и др.). Это особенно удобно для кастомных или самодельных устройств, вроде нашего. Подключение осуществляется через стандартный протокол MQTT, что обеспечивает стабильность, гибкость и полную прозрачность в работе с Zigbee-устройствами. Подробная инструкция по установке и первичной настройке HOMEd доступна в официальной документации проекта (Wiki). Там же описан процесс интеграции с Home Assistant и MQTT-брокером. По умолчанию HOMEd умеет определять популярные Zigbee-устройства автоматически. Однако наши самодельные модули не входят в список известных, поэтому требуется вручную описать их структуру и функциональность. Для этого:
- Перейдите в директорию external, которая находится рядом с файлом конфигурации HOMEd (см. Wiki).
- Внутри папки external создайте новый JSON-файл с произвольным именем, например: my.json.
- В этот файл нужно добавить описание вашего устройства, который HOMEd будет использовать для распознавания и управления модулем.
Вот пример базового содержимого такого JSON-файла для нашего zigbee устройства:
{ "lukjanow.ru": [ { "description": "my_zigbee_switch", "modelNames": ["Zigbee_Switch"], "properties": ["status"], "actions": ["status"], "bindings": ["status"], "exposes": ["switch"], "endpointId": [1, 2, 3] } ] }
- «lukjanow.ru» — имя производите устройства должно совпадать с MANUFACTURER_NAME
- «modelNames»: [«Zigbee_Switch»] имя модели идентификатора устройства так же должно совпадать с MODEL_IDENTIFIER
- «exposes»: [«switch»] тип устройства — переключатель
- «endpointId»: [1, 2, 3] три переключателя, которые мы задали в основной программе.
Внимательно изучите Wiki HOMEd в котором есть полное описание по настройкам и добавлению дополнительных устройств. Запустите Permit Join для сопряжения с координатором. В результате устройство правильно добавится в систему и Вы можете взаимодействовать с ним в Home Assistan.
Код программы основан на данном примере