Skip to content

Commit d45a267

Browse files
committed
feat(zigbee): Recall bound devices after reboot
1 parent 9f5f95e commit d45a267

10 files changed

+309
-91
lines changed

Diff for: libraries/Zigbee/examples/Zigbee_On_Off_Switch/Zigbee_On_Off_Switch.ino

+2-2
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ void setup() {
147147
"IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", device->ieee_addr[0], device->ieee_addr[1], device->ieee_addr[2], device->ieee_addr[3],
148148
device->ieee_addr[4], device->ieee_addr[5], device->ieee_addr[6], device->ieee_addr[7]
149149
);
150-
Serial.printf("Light manufacturer: %s", zbSwitch.readManufacturer(device->endpoint, device->short_addr));
151-
Serial.printf("Light model: %s", zbSwitch.readModel(device->endpoint, device->short_addr));
150+
Serial.printf("Light manufacturer: %s", zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr));
151+
Serial.printf("Light model: %s", zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr));
152152
}
153153

154154
Serial.println();

Diff for: libraries/Zigbee/src/ZigbeeCore.cpp

+67-2
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
243243
} else {
244244
Zigbee._connected = true;
245245
}
246+
Zigbee.searchBindings();
246247
}
247248
} else {
248249
/* commissioning failed */
@@ -309,8 +310,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
309310
Bit 6 – Security capability
310311
Bit 7 – Reserved
311312
*/
312-
313-
// for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices
313+
// for each endpoint in the list call the findEndpoint function if not bounded or allowed to bind multiple devices
314314
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
315315
if (!(*it)->bound() || (*it)->epAllowMultipleBinding()) {
316316
(*it)->findEndpoint(&cmd_req);
@@ -391,6 +391,71 @@ void ZigbeeCore::scanDelete() {
391391
_scan_status = ZB_SCAN_FAILED;
392392
}
393393

394+
// Recall bounded devices from the binding table after reboot
395+
void ZigbeeCore::bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx)
396+
{
397+
bool done = true;
398+
esp_zb_zdo_mgmt_bind_param_t *req = (esp_zb_zdo_mgmt_bind_param_t *)user_ctx;
399+
esp_zb_zdp_status_t zdo_status = (esp_zb_zdp_status_t)table_info->status;
400+
log_d("Binding table callback for address 0x%04x with status %d", req->dst_addr, zdo_status);
401+
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
402+
// Print binding table log simple
403+
log_d("Binding table info: total %d, index %d, count %d", table_info->total, table_info->index, table_info->count);
404+
405+
if(table_info->total == 0) {
406+
log_d("No binding table entries found");
407+
free(req);
408+
return;
409+
}
410+
411+
esp_zb_zdo_binding_table_record_t *record = table_info->record;
412+
for (int i = 0; i < table_info->count; i++) {
413+
log_d("Binding table record: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", record->src_endp, record->dst_endp, record->cluster_id, record->dst_addr_mode);
414+
log_d("Short address: 0x%04x", record->dst_address.addr_short);
415+
log_d("ieee_address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", record->dst_address.addr_long[7], record->dst_address.addr_long[6], record->dst_address.addr_long[5], record->dst_address.addr_long[4], record->dst_address.addr_long[3], record->dst_address.addr_long[2], record->dst_address.addr_long[1], record->dst_address.addr_long[0]);
416+
417+
zb_device_params_t *device = (zb_device_params_t *)calloc(1, sizeof(zb_device_params_t));
418+
device->endpoint = record->dst_endp;
419+
if(record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT || record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT) {
420+
device->short_addr = record->dst_address.addr_short;
421+
} else { //ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT
422+
memcpy(device->ieee_addr, record->dst_address.addr_long, sizeof(esp_zb_ieee_addr_t));
423+
}
424+
log_d("Bound device: endpoint %d, short address 0x%04x to endpoint %d", record->dst_endp, record->dst_address.addr_short, record->src_endp);
425+
426+
// Add to list of bound devices of proper endpoint
427+
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
428+
if ((*it)->getEndpoint() == record->src_endp) {
429+
(*it)->addBoundDevice(device);
430+
}
431+
}
432+
record = record->next;
433+
}
434+
435+
// Continue reading the binding table
436+
if (table_info->index + table_info->count < table_info->total) {
437+
/* There are unreported binding table entries, request for them. */
438+
req->start_index = table_info->index + table_info->count;
439+
esp_zb_zdo_binding_table_req(req, bindingTableCb, req);
440+
done = false;
441+
}
442+
}
443+
444+
if (done) {
445+
// Print bound devices
446+
log_d("Filling bounded devices finished");
447+
free(req);
448+
}
449+
}
450+
451+
void ZigbeeCore::searchBindings(){
452+
esp_zb_zdo_mgmt_bind_param_t *mb_req = (esp_zb_zdo_mgmt_bind_param_t *)malloc(sizeof(esp_zb_zdo_mgmt_bind_param_t));
453+
mb_req->dst_addr = esp_zb_get_short_address();
454+
mb_req->start_index = 0;
455+
log_d("Requesting binding table for address 0x%04x", mb_req->dst_addr);
456+
esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req);
457+
}
458+
394459
// Function to convert enum value to string
395460
const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) {
396461
switch (deviceId) {

Diff for: libraries/Zigbee/src/ZigbeeCore.h

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class ZigbeeCore {
8080
bool zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs);
8181
static void scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor);
8282
const char *getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId);
83+
void searchBindings();
84+
static void bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx);
8385

8486
public:
8587
ZigbeeCore();

Diff for: libraries/Zigbee/src/ZigbeeEP.cpp

+24-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include "esp_zigbee_cluster.h"
88
#include "zcl/esp_zigbee_zcl_power_config.h"
99

10+
#define ZB_CMD_TIMEOUT 10000 // 10 seconds
11+
1012
bool ZigbeeEP::_is_bound = false;
1113
bool ZigbeeEP::_allow_multiple_binding = false;
1214

@@ -112,13 +114,20 @@ void ZigbeeEP::reportBatteryPercentage() {
112114
log_v("Battery percentage reported");
113115
}
114116

115-
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
117+
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
116118
/* Read peer Manufacture Name & Model Identifier */
117119
esp_zb_zcl_read_attr_cmd_t read_req;
118-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
120+
121+
if(short_addr != 0){
122+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
123+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
124+
} else {
125+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
126+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
127+
}
128+
119129
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
120130
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
121-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
122131
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
123132

124133
uint16_t attributes[] = {
@@ -133,19 +142,26 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
133142
esp_zb_zcl_read_attr_cmd_req(&read_req);
134143

135144
//Wait for response or timeout
136-
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
145+
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
137146
log_e("Error while reading manufacturer");
138147
}
139148
return _read_manufacturer;
140149
}
141150

142-
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) {
151+
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
143152
/* Read peer Manufacture Name & Model Identifier */
144153
esp_zb_zcl_read_attr_cmd_t read_req;
145-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
154+
155+
if(short_addr != 0){
156+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
157+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
158+
} else {
159+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
160+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
161+
}
162+
146163
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
147164
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
148-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
149165
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
150166

151167
uint16_t attributes[] = {
@@ -161,7 +177,7 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) {
161177

162178
//Wait for response or timeout
163179
//Semaphore take
164-
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
180+
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
165181
log_e("Error while reading model");
166182
}
167183
return _read_model;

Diff for: libraries/Zigbee/src/ZigbeeEP.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ class ZigbeeEP {
8787
void reportBatteryPercentage();
8888

8989
// Methods to read manufacturer and model name from selected endpoint and short address
90-
char *readManufacturer(uint8_t endpoint, uint16_t short_addr);
91-
char *readModel(uint8_t endpoint, uint16_t short_addr);
90+
char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
91+
char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
9292

9393
bool epAllowMultipleBinding() {
9494
return _allow_multiple_binding;
@@ -108,7 +108,7 @@ class ZigbeeEP {
108108
}
109109

110110
private:
111-
static bool _allow_multiple_binding;
111+
112112
char *_read_manufacturer;
113113
char *_read_model;
114114
void (*_on_identify)(uint16_t time);
@@ -119,10 +119,16 @@ class ZigbeeEP {
119119
esp_zb_endpoint_config_t _ep_config;
120120
esp_zb_cluster_list_t *_cluster_list;
121121
static bool _is_bound;
122+
static bool _allow_multiple_binding;
122123
std::list<zb_device_params_t *> _bound_devices;
123124
SemaphoreHandle_t lock;
124125
zb_power_source_t _power_source;
125126

127+
void addBoundDevice(zb_device_params_t *device) {
128+
_bound_devices.push_back(device);
129+
_is_bound = true;
130+
}
131+
126132
friend class ZigbeeCore;
127133
};
128134

0 commit comments

Comments
 (0)