feat(zigbee): Save network channel after 1st joining for faster rejoin (#11123)
* feat(zigbee): Save network channel after 1st joining for faster rejoin * ci(pre-commit): Apply automatic fixes * feat(zigbee): Add channel mask reset after timeout * feat(zigbee): Add the resetChannelMask to all Begin methods * feaz(zigbee): Move function to private and add set method * fix(example): Remove test from device mode name * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
parent
8e62997bfd
commit
e2915c48e8
4 changed files with 55 additions and 9 deletions
|
|
@ -77,7 +77,7 @@ void setup() {
|
|||
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
|
||||
|
||||
// Optional: set Zigbee device name and model
|
||||
zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest");
|
||||
zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor");
|
||||
|
||||
// Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement)
|
||||
zbTempSensor.setMinMaxValue(10, 50);
|
||||
|
|
@ -99,11 +99,15 @@ void setup() {
|
|||
esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG();
|
||||
zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000;
|
||||
|
||||
// For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery
|
||||
// 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)
|
||||
Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s)
|
||||
|
||||
// When all EPs are registered, start Zigbee in End Device mode
|
||||
if (!Zigbee.begin(&zigbeeConfig, false)) {
|
||||
Serial.println("Zigbee failed to start!");
|
||||
Serial.println("Rebooting...");
|
||||
ESP.restart();
|
||||
ESP.restart(); // If Zigbee failed to start, reboot the device and try again
|
||||
}
|
||||
Serial.println("Connecting to network");
|
||||
while (!Zigbee.connected()) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,16 @@
|
|||
#include "ZigbeeHandlers.cpp"
|
||||
#include "Arduino.h"
|
||||
|
||||
#define ZB_INIT_TIMEOUT 30000 // 30 seconds
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "zboss_api.h"
|
||||
extern zb_ret_t zb_nvram_write_dataset(zb_nvram_dataset_types_t t); // rejoin scanning workaround
|
||||
extern void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr); // sleepy device power mode workaround
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr);
|
||||
static bool edBatteryPowered = false;
|
||||
|
||||
ZigbeeCore::ZigbeeCore() {
|
||||
|
|
@ -18,6 +25,7 @@ ZigbeeCore::ZigbeeCore() {
|
|||
_primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK;
|
||||
_open_network = 0;
|
||||
_scan_status = ZB_SCAN_FAILED;
|
||||
_begin_timeout = ZB_BEGIN_TIMEOUT_DEFAULT;
|
||||
_started = false;
|
||||
_connected = false;
|
||||
_scan_duration = 3; // default scan duration
|
||||
|
|
@ -39,8 +47,11 @@ bool ZigbeeCore::begin(esp_zb_cfg_t *role_cfg, bool erase_nvs) {
|
|||
return false;
|
||||
}
|
||||
_role = (zigbee_role_t)role_cfg->esp_zb_role;
|
||||
if (xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
|
||||
log_e("ZigbeeCore begin timeout");
|
||||
if (xSemaphoreTake(lock, _begin_timeout) != pdTRUE) {
|
||||
log_e("ZigbeeCore begin failed or timeout");
|
||||
if (_role != ZIGBEE_COORDINATOR) { // Only End Device and Router can rejoin
|
||||
resetNVRAMChannelMask();
|
||||
}
|
||||
}
|
||||
return started();
|
||||
}
|
||||
|
|
@ -71,8 +82,11 @@ bool ZigbeeCore::begin(zigbee_role_t role, bool erase_nvs) {
|
|||
}
|
||||
default: log_e("Invalid Zigbee Role"); return false;
|
||||
}
|
||||
if (!status || xSemaphoreTake(lock, ZB_INIT_TIMEOUT) != pdTRUE) {
|
||||
if (!status || xSemaphoreTake(lock, _begin_timeout) != pdTRUE) {
|
||||
log_e("ZigbeeCore begin failed or timeout");
|
||||
if (_role != ZIGBEE_COORDINATOR) { // Only End Device and Router can rejoin
|
||||
resetNVRAMChannelMask();
|
||||
}
|
||||
}
|
||||
return started();
|
||||
}
|
||||
|
|
@ -220,6 +234,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
|
|||
switch (sig_type) {
|
||||
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: // Common
|
||||
log_i("Zigbee stack initialized");
|
||||
log_d("Zigbee channel mask: 0x%08x", esp_zb_get_channel_mask());
|
||||
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
|
||||
break;
|
||||
case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Common
|
||||
|
|
@ -245,6 +260,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
|
|||
log_i("Opening network for joining for %d seconds", Zigbee._open_network);
|
||||
esp_zb_bdb_open_network(Zigbee._open_network);
|
||||
} else {
|
||||
// Save the channel mask to NVRAM in case of reboot which may be on a different channel after a change in the network
|
||||
Zigbee.setNVRAMChannelMask(1 << esp_zb_get_current_channel());
|
||||
Zigbee._connected = true;
|
||||
}
|
||||
Zigbee.searchBindings();
|
||||
|
|
@ -289,6 +306,8 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
|
|||
extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address()
|
||||
);
|
||||
Zigbee._connected = true;
|
||||
// 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)
|
||||
Zigbee.setNVRAMChannelMask(1 << esp_zb_get_current_channel());
|
||||
} else {
|
||||
log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status));
|
||||
esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
|
||||
|
|
@ -483,6 +502,20 @@ void ZigbeeCore::searchBindings() {
|
|||
esp_zb_zdo_binding_table_req(mb_req, bindingTableCb, (void *)mb_req);
|
||||
}
|
||||
|
||||
void ZigbeeCore::resetNVRAMChannelMask() {
|
||||
_primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK;
|
||||
esp_zb_set_channel_mask(_primary_channel_mask);
|
||||
zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA);
|
||||
log_v("Channel mask reset to all channels");
|
||||
}
|
||||
|
||||
void ZigbeeCore::setNVRAMChannelMask(uint32_t mask) {
|
||||
_primary_channel_mask = mask;
|
||||
esp_zb_set_channel_mask(_primary_channel_mask);
|
||||
zb_nvram_write_dataset(ZB_NVRAM_COMMON_DATA);
|
||||
log_v("Channel mask set to 0x%08x", mask);
|
||||
}
|
||||
|
||||
// Function to convert enum value to string
|
||||
const char *ZigbeeCore::getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId) {
|
||||
switch (deviceId) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ typedef enum {
|
|||
#define ZB_SCAN_RUNNING (-1)
|
||||
#define ZB_SCAN_FAILED (-2)
|
||||
|
||||
#define ZB_BEGIN_TIMEOUT_DEFAULT 30000 // 30 seconds
|
||||
|
||||
#define ZIGBEE_DEFAULT_ED_CONFIG() \
|
||||
{ \
|
||||
.esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, .install_code_policy = false, \
|
||||
|
|
@ -85,6 +87,7 @@ private:
|
|||
esp_zb_radio_config_t _radio_config;
|
||||
esp_zb_host_config_t _host_config;
|
||||
uint32_t _primary_channel_mask;
|
||||
uint32_t _begin_timeout;
|
||||
int16_t _scan_status;
|
||||
uint8_t _scan_duration;
|
||||
bool _rx_on_when_idle;
|
||||
|
|
@ -103,6 +106,8 @@ private:
|
|||
const char *getDeviceTypeString(esp_zb_ha_standard_devices_t deviceId);
|
||||
void searchBindings();
|
||||
static void bindingTableCb(const esp_zb_zdo_binding_table_info_t *table_info, void *user_ctx);
|
||||
void resetNVRAMChannelMask(); // Reset to default mask also in NVRAM
|
||||
void setNVRAMChannelMask(uint32_t mask); // Set channel mask in NVRAM
|
||||
|
||||
public:
|
||||
ZigbeeCore();
|
||||
|
|
@ -134,7 +139,8 @@ public:
|
|||
esp_zb_host_config_t getHostConfig();
|
||||
|
||||
void setPrimaryChannelMask(uint32_t mask); // By default all channels are scanned (11-26) -> mask 0x07FFF800
|
||||
void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest
|
||||
|
||||
void setScanDuration(uint8_t duration); // Can be set from 1 - 4. 1 is fastest, 4 is slowest
|
||||
uint8_t getScanDuration() {
|
||||
return _scan_duration;
|
||||
}
|
||||
|
|
@ -145,7 +151,9 @@ public:
|
|||
bool getRxOnWhenIdle() {
|
||||
return _rx_on_when_idle;
|
||||
}
|
||||
|
||||
void setTimeout(uint32_t timeout) {
|
||||
_begin_timeout = timeout;
|
||||
}
|
||||
void setRebootOpenNetwork(uint8_t time);
|
||||
void openNetwork(uint8_t time);
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ void ZigbeeEP::reportBatteryPercentage() {
|
|||
report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
|
||||
report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG;
|
||||
report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
|
||||
report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;
|
||||
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
|
||||
|
|
|
|||
Loading…
Reference in a new issue