Skip to content

Commit 97643ec

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

10 files changed

+312
-89
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

+68-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,72 @@ 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+
// Create a new device object and fill it with the binding table info
412+
zb_device_params_t *device = (zb_device_params_t *)malloc(sizeof(zb_device_params_t));
413+
device->endpoint = table_info->record->dst_endp;
414+
415+
//log all tableinfo record
416+
log_d("Binding table record: src_endp %d, dst_endp %d, cluster_id 0x%04x, dst_addr_mode %d", table_info->record->src_endp, table_info->record->dst_endp, table_info->record->cluster_id, table_info->record->dst_addr_mode);
417+
log_d("Short address: 0x%04x", table_info->record->dst_address.addr_short);
418+
log_d("ieee_address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", table_info->record->dst_address.addr_long[7], table_info->record->dst_address.addr_long[6], table_info->record->dst_address.addr_long[5], table_info->record->dst_address.addr_long[4], table_info->record->dst_address.addr_long[3], table_info->record->dst_address.addr_long[2], table_info->record->dst_address.addr_long[1], table_info->record->dst_address.addr_long[0]);
419+
420+
if(table_info->record->dst_addr_mode == ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT ) {
421+
device->short_addr = table_info->record->dst_address.addr_short;
422+
} else { //ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT
423+
memcpy(device->ieee_addr, table_info->record->dst_address.addr_long, sizeof(esp_zb_ieee_addr_t));
424+
}
425+
426+
log_d("Bound device: endpoint %d, short address 0x%04x to endpoint %d", table_info->record->dst_endp, table_info->record->dst_address.addr_short, table_info->record->src_endp);
427+
428+
// Add to list of bound devices of proper endpoint
429+
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
430+
if ((*it)->getEndpoint() == table_info->record->src_endp) {
431+
(*it)->addBoundDevice(device);
432+
}
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+
452+
void ZigbeeCore::searchBindings(){
453+
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));
454+
mb_req->dst_addr = esp_zb_get_short_address();
455+
mb_req->start_index = 0;
456+
log_d("Requesting binding table for address 0x%04x", mb_req->dst_addr);
457+
esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req);
458+
}
459+
394460
// Function to convert enum value to string
395461
const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) {
396462
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

+20-6
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,20 @@ void ZigbeeEP::reportBatteryPercentage() {
112112
log_v("Battery percentage reported");
113113
}
114114

115-
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
115+
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
116116
/* Read peer Manufacture Name & Model Identifier */
117117
esp_zb_zcl_read_attr_cmd_t read_req;
118-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
118+
119+
if(short_addr != 0){
120+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
121+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
122+
} else {
123+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
124+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
125+
}
126+
119127
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
120128
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
121-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
122129
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
123130

124131
uint16_t attributes[] = {
@@ -139,13 +146,20 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr) {
139146
return _read_manufacturer;
140147
}
141148

142-
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr) {
149+
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
143150
/* Read peer Manufacture Name & Model Identifier */
144151
esp_zb_zcl_read_attr_cmd_t read_req;
145-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
152+
153+
if(short_addr != 0){
154+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
155+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
156+
} else {
157+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
158+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
159+
}
160+
146161
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
147162
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
148-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
149163
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
150164

151165
uint16_t attributes[] = {

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)