Skip to content

Commit 1ff918b

Browse files
committed
feat(zigbee): Add channel mask reset after timeout
1 parent 1908c6e commit 1ff918b

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino

+5-1
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,15 @@ void setup() {
9999
esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG();
100100
zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000;
101101

102+
// For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery
103+
// If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels)
104+
Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s)
105+
102106
// When all EPs are registered, start Zigbee in End Device mode
103107
if (!Zigbee.begin(&zigbeeConfig, false)) {
104108
Serial.println("Zigbee failed to start!");
105109
Serial.println("Rebooting...");
106-
ESP.restart();
110+
ESP.restart(); // If Zigbee failed to start, reboot the device and try again
107111
}
108112
Serial.println("Connecting to network");
109113
while (!Zigbee.connected()) {

libraries/Zigbee/src/ZigbeeCore.cpp

+19-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
#include "ZigbeeHandlers.cpp"
77
#include "Arduino.h"
88

9-
#define ZB_INIT_TIMEOUT 30000 // 30 seconds
10-
119
#ifdef __cplusplus
1210
extern "C" {
1311
#endif
@@ -27,6 +25,7 @@ ZigbeeCore::ZigbeeCore() {
2725
_primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK;
2826
_open_network = 0;
2927
_scan_status = ZB_SCAN_FAILED;
28+
_begin_timeout = ZB_BEGIN_TIMEOUT_DEFAULT;
3029
_started = false;
3130
_connected = false;
3231
_scan_duration = 3; // default scan duration
@@ -48,7 +47,7 @@ bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) {
4847
return false;
4948
}
5049
_role = (zigbee_role_t)role_cfg->esp_zb_role;
51-
if (xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
50+
if (xSemaphoreTake(lock, _begin_timeout) != pdTRUE) {
5251
log_e("ZigbeeCore begin timeout");
5352
}
5453
return started();
@@ -80,8 +79,11 @@ bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) {
8079
}
8180
default: log_e("Invalid Zigbee Role"); return false;
8281
}
83-
if (!status || xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
82+
if (!status || xSemaphoreTake(lock, _begin_timeout) != pdTRUE) {
8483
log_e("ZigbeeCore begin failed or timeout");
84+
if(role != ZIGBEE_COORDINATOR) { // Only End Device and Router can rejoin
85+
resetChannelMask();
86+
}
8587
}
8688
return started();
8789
}
@@ -229,6 +231,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
229231
switch (sig_type) {
230232
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: // Common
231233
log_i("Zigbee stack initialized");
234+
log_d("Zigbee channel mask: 0x%08x", esp_zb_get_channel_mask());
232235
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
233236
break;
234237
case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Common
@@ -254,6 +257,10 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
254257
log_i("Opening network for joining for %d seconds", Zigbee._open_network);
255258
esp_zb_bdb_open_network(Zigbee._open_network);
256259
} else {
260+
// Save the channel mask to NVRAM in case of reboot which may be on a different channel after a change in the network
261+
Zigbee.setPrimaryChannelMask(1 << esp_zb_get_current_channel());
262+
esp_zb_set_channel_mask(1 << esp_zb_get_current_channel());
263+
zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA);
257264
Zigbee._connected = true;
258265
}
259266
Zigbee.searchBindings();
@@ -299,7 +306,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
299306
);
300307
Zigbee._connected = true;
301308
// Set channel mask and write to NVRAM, so that the device will re-join the network faster after reboot (scan only on the current channel)
302-
esp_zb_set_channel_mask((1 << esp_zb_get_current_channel()));
309+
Zigbee.setPrimaryChannelMask(1 << esp_zb_get_current_channel());
310+
esp_zb_set_channel_mask(1 << esp_zb_get_current_channel());
303311
zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA);
304312
} else {
305313
log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status));
@@ -495,6 +503,12 @@ void ZigbeeCore::searchBindings() {
495503
esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req);
496504
}
497505

506+
void ZigbeeCore::resetChannelMask() {
507+
_primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK;
508+
esp_zb_set_channel_mask(_primary_channel_mask);
509+
zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA);
510+
log_v("Channel mask reset to all channels");
511+
}
498512
// Function to convert enum value to string
499513
const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) {
500514
switch (deviceId) {

libraries/Zigbee/src/ZigbeeCore.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ typedef enum {
2828
#define ZB_SCAN_RUNNING (-1)
2929
#define ZB_SCAN_FAILED (-2)
3030

31+
#define ZB_BEGIN_TIMEOUT_DEFAULT 30000 // 30 seconds
32+
3133
#define ZIGBEE_DEFAULT_ED_CONFIG() \
3234
{ \
3335
.esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = false, \
@@ -85,6 +87,7 @@ class ZigbeeCore {
8587
esp_zb_radio_config_t _radio_config;
8688
esp_zb_host_config_t _host_config;
8789
uint32_t _primary_channel_mask;
90+
uint32_t _begin_timeout;
8891
int16_t _scan_status;
8992
uint8_t _scan_duration;
9093
bool _rx_on_when_idle;
@@ -134,6 +137,8 @@ class ZigbeeCore {
134137
esp_zb_host_config_t getHostConfig();
135138

136139
void setPrimaryChannelMask(uint32_t mask); // By default all channels are scanned (11-26) -> mask 0x07FFF800
140+
void resetChannelMask(); // Reset to default mask also in NVRAM
141+
137142
void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest
138143
uint8_t getScanDuration() {
139144
return _scan_duration;
@@ -145,7 +150,9 @@ class ZigbeeCore {
145150
bool getRxOnWhenIdle() {
146151
return _rx_on_when_idle;
147152
}
148-
153+
void setTimeout(uint32_t timeout) {
154+
_begin_timeout = timeout;
155+
}
149156
void setRebootOpenNetwork(uint8_t time);
150157
void openNetwork(uint8_t time);
151158

libraries/Zigbee/src/ZigbeeEP.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ void ZigbeeEP::reportBatteryPercentage() {
104104
report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
105105
report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG;
106106
report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
107+
report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;
107108

108109
esp_zb_lock_acquire(portMAX_DELAY);
109110
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);

0 commit comments

Comments
 (0)