Собственный zigbee2mqtt на C++ с бустом и исключениями
Домашняя автоматизация — вещь неоднозначная, каждый понимает под ней что-то свое: для кого-то это подключить обогреватель через wi-fi розетку, а кому-то подавай домашний сервер, километры кабеля, KNX и часы работы интеграторов. Если в городских квартирах система «умный дом» — не всегда благо, то для загородного дома или дачи необходимость ее наличия сильно возрастает: проконтролировать отопление, выключить свет или разогреть электропечку в любимой сауне перед приездом. При этом такая система должна быть простой, дешевой и уметь работать автономно: никто не хочет приехать в промёрзший из-за упавшего интернета дом. А что нужно сделать, если готовые решения полностью не устраивают, правильно — написать самому…
Для объединенеия устройств был выбран протокол zigbee по двум причинам: во-первых он беспроводной, а на даче никто не желает тратится на лишние коммуникации, а во-вторых он довольно энергоэффективный и какой-нибудь датчик или выкючатель может питаться от батареи CR2032 несколько лет без необходимости подводить внешнее питание.
Изначальной идеей было прикрутить к проекту zigbee2mqtt свой мини-сервер и повесить на него всю логику по управлению умным домом (хотя скорее дачей). Минусы такого подхода: во-первых вторично, а во вторых это отдельно сервер, отдельно zigbee2mqtt и отдельно mqtt брокер для объединения, что очевидно надежности не добавляет. Поэтому первое, к написанию чего пришлось приступить — это собственная библиотека для работы с zigbee сетью на одном из самых популярных и доступных zigbee контроллеров cc2531 от Texas Instruments.
С документацией по zigbee чипам ситуация неоднозначная — она есть, она довольно подробная, многие нюансы хорошо описаны, из нее совершенно не понятно как все работает и что с этим делать. Так с cc2531 было понятно как организовать обмен командами с контроллером, но его инициализация и настройка в роли координатора не описаны нормально нигде. После безуспешных поисков по иностранным форумам я понял, что проще изучить работу на живом чипе, благо в SDK к нему есть утилита Z-tool, позволяющая в ручном режиме слать команды и смотреть ответы.
Правда очень быстро выяснилось, что свежезапущенный контроллер не собирается как-то работать с ранее спаренными с ним устройствами (кнопка Xiaomi WXKG01LM и датчик температуры WSDCGQ01LM и т.д.).
При этом zigbee2mqtt корректно работал с ними обоими. Самым быстрым способом начать работать через Z-tool оказалось сначала запустить zigbee2mqtt, дать ему сделать все, что он должен сделать, а потом закрыть его и, не перезагружая контроллер, подключиться через утилиту. И, как ни странно, этот способ заработал.
В итоге довольно-таки быстро удалось понять логику работы при приеме сообщений, спаривании устройств и т.д., но двигаться дальше без инициализации было невозможно.
В течении нескольких дней я копался в исходниках zigbee2mqtt, однако полностью логику понять не удалось, тем более она размыта между самим проектом Koenkk и его отдельными модулями для работы zigbee (zigbee-herdsman и zigbee-herdsman-converters). Решив, что лучше зайти со стороны реверс-инжинеринга zigbee2mqtt был запущен через сниффер порта Advanced Serial Port Monitor, а дамп его работы записан в файл.
Вскоре был написан парсер, выдававший что-то более читаемое из дампа и началась работа по воссозданию логики работы:
SYS_PING : ;
SYS_PING_SRSP : 0x79 0x7 ;
SYS_VERSION : ;
SYS_VERSION_SRSP : 0x2 0x2 0x2 0x7 0x2 0xd9 0x14 0x34 0x1 0x2 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x60 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x55 ;
SYS_OSAL_NV_READ : 0x60 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x55 ;
SYS_OSAL_NV_READ : 0x84 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x4 0x0 0x8 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x63 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x0 ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
UTIL_GET_DEVICE_INFO : ;
UTIL_GET_DEVICE_INFO_SRSP : 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0x0 0x0 0x7 0x9 0x4 0x7d 0x14 0x7a 0x43 0x82 0x85 0xa0 0x45 ;
ZDO_ACTIVE_EP_REQ : 0x0 0x0 0x0 0x0 ;
ZDO_ACTIVE_EP_SRSP : 0x0 ;
ZDO_ACTIVE_EP_RSP : 0x0 0x0 0x0 0x0 0x0 0xe 0xf2 0x2f 0xd 0xc 0x6e 0xb 0xa 0x8 0x6 0x5 0x4 0x3 0x2 0x1 ;
ZDO_ACTIVE_EP_REQ : 0x0 0x0 0x0 0x0 ;
ZDO_ACTIVE_EP_SRSP : 0x0 ;
ZDO_ACTIVE_EP_RSP : 0x0 0x0 0x0 0x0 0x0 0xe 0xf2 0x2f 0xd 0xc 0x6e 0xb 0xa 0x8 0x6 0x5 0x4 0x3 0x2 0x1 ;
UTIL_GET_DEVICE_INFO : ;
UTIL_GET_DEVICE_INFO_SRSP : 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0x0 0x0 0x7 0x9 0x4 0x7d 0x14 0x7a 0x43 0x82 0x85 0xa0 0x45 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xf2 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xf2 0xe0 0xa1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x2f ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x2f 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xd ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0xa 0xd 0x4 0x1 0x5 0x0 0x0 0x1 0x19 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xc ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xc 0x5e 0xc0 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x6e ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x6e 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xb ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0xe 0xb 0x4 0x1 0x0 0x4 0x0 0x1 0x1 0x5 0x2 0x0 0x5 0x2 0x5 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xa ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xa 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x8 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x8 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x6 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x6 0x9 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x5 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x5 0x8 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x4 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x4 0x7 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x3 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x3 0x5 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x2 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x2 0x1 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x1 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x1 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
SYS_VERSION : ;
SYS_VERSION_SRSP : 0x2 0x2 0x2 0x7 0x2 0xd9 0x14 0x34 0x1 0x2 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x1 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 ;
SYS_OSAL_NV_READ : 0x21 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x6e 0x4f 0x5 0x2 0x10 0x14 0x10 0x0 0x14 0x0 0x0 0x0 0x1 0x5 0x1 0x8f 0x7 0x0 0x2 0x5 0x1e 0x0 0x0 0xb 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x62 0x1a 0x8 0x0 0x8 0x0 0x0 0xf 0xf 0x4 0x0 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3c 0x3 0x0 0x1 0x78 0xa 0x1 0x0 0x0 0x1d 0xf 0x0 ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
SYS_OSAL_NV_READ : 0x2d 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd ;
SYS_OSAL_NV_READ : 0x3a 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x11 0x0 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x3b 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x11 0x0 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x47 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x62 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x10 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x63 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x0 ;
SYS_OSAL_NV_READ : 0x84 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x4 0x0 0x8 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x11 0x1 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x13 0x1e 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x75 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0xc 0x35 0x34 0x2f 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 ;
ZDO_MGMT_PERMIT_JOIN_REQ : 0xf 0xfc 0xff 0xfe 0x0 ;
ZDO_MGMT_PERMIT_JOIN_SRSP : 0x0 ;
ZDO_MGMT_PERMIT_JOIN_RSP : 0x0 0x0 0x0 ;
AF_DATA_CONFIRM : 0x0 0xf2 0x1 ;
SYS_PING : ;
SYS_PING_SRSP : 0x79 0x7 ;
SYS_VERSION : ;
SYS_VERSION_SRSP : 0x2 0x2 0x2 0x7 0x2 0xd9 0x14 0x34 0x1 0x2 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x60 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x55 ;
SYS_OSAL_NV_READ : 0x60 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x55 ;
SYS_OSAL_NV_READ : 0x84 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x4 0x0 0x8 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x63 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x0 ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
UTIL_GET_DEVICE_INFO : ;
UTIL_GET_DEVICE_INFO_SRSP : 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0xfe 0xff 0x7 0x0 0x0 ;
ZDO_STARTUP_FROM_APP : 0x64 0x0 ;
ZDO_STARTUP_FROM_APP_SRSP : 0x0 ;
ZDO_STATE_CHANGE_IND : 0x9 ;
ZDO_ACTIVE_EP_REQ : 0x0 0x0 0x0 0x0 ;
ZDO_ACTIVE_EP_SRSP : 0x0 ;
ZDO_ACTIVE_EP_RSP : 0x0 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER : 0x1 0x4 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x2 0x1 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x3 0x5 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x4 0x7 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x5 0x8 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x6 0x9 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x8 0x4 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0xa 0x4 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0xb 0x4 0x1 0x0 0x4 0x0 0x0 0x1 0x1 0x5 0x2 0x0 0x5 0x2 0x5 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x6e 0x4 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0xc 0x5e 0xc0 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0xd 0x4 0x1 0x5 0x0 0x0 0x0 0x1 0x19 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0x2f 0x4 0x1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
AF_REGISTER : 0xf2 0xe0 0xa1 0x5 0x0 0x0 0x0 0x0 0x0 ;
AF_REGISTER_SRSP : 0x0 ;
ZDO_ACTIVE_EP_REQ : 0x0 0x0 0x0 0x0 ;
ZDO_ACTIVE_EP_SRSP : 0x0 ;
ZDO_ACTIVE_EP_RSP : 0x0 0x0 0x0 0x0 0x0 0xe 0xf2 0x2f 0xd 0xc 0x6e 0xb 0xa 0x8 0x6 0x5 0x4 0x3 0x2 0x1 ;
UTIL_GET_DEVICE_INFO : ;
UTIL_GET_DEVICE_INFO_SRSP : 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0x0 0x0 0x7 0x9 0x4 0x7d 0x14 0x7a 0x43 0x82 0x85 0xa0 0x45 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xf2 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xf2 0xe0 0xa1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x2f ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x2f 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xd ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0xa 0xd 0x4 0x1 0x5 0x0 0x0 0x1 0x19 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xc ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xc 0x5e 0xc0 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x6e ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x6e 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xb ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0xe 0xb 0x4 0x1 0x0 0x4 0x0 0x1 0x1 0x5 0x2 0x0 0x5 0x2 0x5 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0xa ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0xa 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x8 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x8 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x6 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x6 0x9 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x5 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x5 0x8 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x4 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x4 0x7 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x3 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x3 0x5 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x2 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x2 0x1 0x1 0x5 0x0 0x0 0x0 0x0 ;
ZDO_SIMPLE_DESC_REQ : 0x0 0x0 0x0 0x0 0x1 ;
ZDO_SIMPLE_DESC_SRSP : 0x0 ;
ZDO_SIMPLE_DESC_RSP : 0x0 0x0 0x0 0x0 0x0 0x8 0x1 0x4 0x1 0x5 0x0 0x0 0x0 0x0 ;
SYS_VERSION : ;
SYS_VERSION_SRSP : 0x2 0x2 0x2 0x7 0x2 0xd9 0x14 0x34 0x1 0x2 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x1 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 ;
SYS_OSAL_NV_READ : 0x21 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x6e 0x4f 0x5 0x2 0x10 0x14 0x10 0x0 0x14 0x0 0x0 0x0 0x1 0x5 0x1 0x8f 0x7 0x0 0x2 0x5 0x1e 0x0 0x0 0xb 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x62 0x1a 0x8 0x0 0x8 0x0 0x0 0xf 0xf 0x4 0x0 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3c 0x3 0x0 0x1 0x78 0xa 0x1 0x0 0x0 0x1d 0xf 0x0 ;
SYS_OSAL_NV_READ : 0x83 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x2 0xff 0xff ;
SYS_OSAL_NV_READ : 0x2d 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd ;
SYS_OSAL_NV_READ : 0x3a 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x11 0x0 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x3b 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x11 0x0 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x47 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x62 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x10 0x1 0x3 0x5 0x7 0x9 0xb 0xd 0xf 0x0 0x2 0x4 0x6 0x8 0xa 0xc 0xd ;
SYS_OSAL_NV_READ : 0x63 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x1 0x0 ;
SYS_OSAL_NV_READ : 0x84 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x4 0x0 0x8 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x11 0x1 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0x13 0x29 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff 0x0 0x0 ;
SYS_OSAL_NV_READ : 0x75 0x0 0x0 ;
SYS_OSAL_NV_READ_SRSP : 0x0 0xc 0x17 0x39 0x2f 0x0 0xf0 0xa6 0x38 0x19 0x0 0x4b 0x12 0x0 ;
ZDO_MGMT_PERMIT_JOIN_REQ : 0xf 0xfc 0xff 0xfe 0x0 ;
ZDO_MGMT_PERMIT_JOIN_SRSP : 0x0 ;
ZDO_MGMT_PERMIT_JOIN_RSP : 0x0 0x0 0x0 ;
AF_DATA_CONFIRM : 0x0 0xf2 0x1 ;
Итого, чтобы запустить ZNP в роли координатора минимально необходимо:
записать настройки в энергонезависимую память контроллера, по идее делается один раз при первом включении
перезагрузить
стартовать работу командой
ZDO_STARTUP_FROM_APP
зарегистрировать стандартные эндпоинты (хватит одного под номером один для профиля домашней автоматизации
0x0104
)
Изучение дампа обмена zigbee2mqtt не раз выручало меня и дальше при проблемах в инициализации подключаемых к сети устройств.
Через какое-то время zigbee-часть мини-сервера домашней автоматизации была написана на C++ с использованием Boost.Asio, а к ней прикручена логика, объединяющая устройства в функциональные узлы (например узел отопления может объединять реле и датчик температуры). Но всем этим нужно управлять как минимум для подключения устройств, а как максимум для полноценного контроля через интернет. В итоге протоколом для второго конца системы был выбран … mqtt (через библиотеку mqtt_cpp), и мини-сервер в каком-то роде стал еще больше похож на проект zigbee2mqtt с которого все начиналось.
С исходниками и более детальным описанием проекта можно ознакомится на github.