-
Notifications
You must be signed in to change notification settings - Fork 75
Description
Question
I am developing a Zigbee Enddevice with an ESP32C6 which has 2 Endpoints (each one has an AnalogInput Cluster and some others too). Everything works fine without adding the LightSleep functionality. For the Project I need the LightSleep functionality but as soon as I add this esp_zb_sleep_enable(true), my ESP isnt connecting anymore with the zigbee network (Steering forever). The power management configuration (like in the official LightSleep example) and some wakeup stuff is already present in my project and works fine (also tested without zigbee):
- CONFIG_PM_ENABLE=y
- CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
- CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
- CONFIG_IEEE802154_SLEEP_ENABLE=y
- CONFIG_FREERTOS_HZ=1000
void px_init_power_management(void) {
esp_pm_config_t pm_config = {
.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
.min_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
.light_sleep_enable = true // light sleep will be automatically entered when the system is idle and no tasks are running (freertos idle)
};
ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
}
uint64_t pin_mask = (1ULL << PIN_WAKEUP_FROM_BUTTON);
esp_sleep_enable_ext1_wakeup(pin_mask, ESP_EXT1_WAKEUP_ANY_HIGH);
Power Profile with esp_zb_sleep_enable(true) while Network Steering results in no connection.
You can see 16 Spikes (I guess for every Channel) and then entering LightSleep:

Power Profile with esp_zb_sleep_enable(false) while Network Steering results in successfull interview and than configuring which ends also successfull.
You can see the same 16 Spikes but than there is another one (maybe the answer from the coordinator?). Interview+Configuring takes about 4 seconds:

To verify my Board and stuff I have tested with the official LightSleep example which connects fine (but takes a quite long time during configuring (although it only has 1 EP...)). Interview+Configuring took about 14 seconds:

Main Programm:
void app_main(void) {
ESP_LOGI(TAG, "System starting in Light-Sleep Mode...");
// Init synchronization
sem_button_event = xSemaphoreCreateBinary(); // This semaphore is given by the button monitoring task when a button event is detected, and taken by the button_logic_task when it starts processing the event.
// Init power management and wakeup sources and GPIO interrupts
px_init_power_management(); // Configure power management to allow light sleep
setup_wakeup_and_interrupts();
// Start tasks
//xTaskCreate(msp_worker_task, "msp_task", 4096, NULL, 10, NULL);
xTaskCreate(button_logic_task, "btn_task", 4096, NULL, 5, NULL); // Also tried without this task
px_zigbee_init();
xTaskCreate(px_zigbee_start, "Zigbee_main", 4096, NULL, 15, NULL); // Start Zigbee in a separate task (needs larger stack)
ESP_LOGI(TAG, "Initialization finished. Entering Event-Loop.");
// app_main ends here, the tasks run indefinitely in the background, while the main function can return and the system can enter light sleep when idle.
// ends the main task
vTaskDelete(NULL);
}
// --- INTERRUPT & WAKEUP SETUP ---
static void IRAM_ATTR gpio_isr_handler(void* arg) {
uint32_t gpio_num = (uint32_t) arg;
if (gpio_num == PIN_WAKEUP_FROM_BUTTON) { // Button Pin
gpio_intr_disable(PIN_WAKEUP_FROM_BUTTON); // Disable further interrupts from this pin until we have processed the current one to avoid flooding
xSemaphoreGiveFromISR(sem_button_event, NULL);
}
}
// Sets up that the ESP32 wakes up (from light sleep and deep sleep) when either the MSP430 triggers the wakeup pin or when the user presses the button
// and also sets up GPIO interrupts for both pins to handle events while the ESP is awake
void setup_wakeup_and_interrupts(void) {
// Configure GPIOs as inputs (first WITHOUT interrupts to avoid triggering interrupts during setup)
gpio_config_t msp_conf = {
.pin_bit_mask = (1ULL << PIN_WAKEUP_FROM_MSP),
.mode = GPIO_MODE_INPUT,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&msp_conf);
gpio_config_t btn_conf = {
.pin_bit_mask = (1ULL << PIN_WAKEUP_FROM_BUTTON),
.mode = GPIO_MODE_INPUT,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&btn_conf);
// Configure Wakeup (wake up when button is pressed or when MSP430 triggers pin, wakeups lightsleep and deepsleep)
uint64_t pin_mask = (1ULL << PIN_WAKEUP_FROM_BUTTON); // | (1ULL << PIN_WAKEUP_FROM_MSP);
esp_sleep_enable_ext1_wakeup(pin_mask, ESP_EXT1_WAKEUP_ANY_HIGH);
// Step 3: Install ISR service
ESP_ERROR_CHECK(gpio_install_isr_service(0));
// Add ISR handlers
ESP_ERROR_CHECK(gpio_isr_handler_add(PIN_WAKEUP_FROM_BUTTON, gpio_isr_handler, (void*) PIN_WAKEUP_FROM_BUTTON));
// Enable interrupts on the pins
ESP_ERROR_CHECK(gpio_set_intr_type(PIN_WAKEUP_FROM_BUTTON, GPIO_INTR_HIGH_LEVEL));
ESP_LOGI(TAG, "GPIO wakeup and interrupts configured successfully");
}
// --- TASK IMPLEMENTATIONS ---
void button_logic_task(void *pv) {
while(1) {
if (xSemaphoreTake(sem_button_event, portMAX_DELAY)) {
vTaskDelay(pdMS_TO_TICKS(50)); // Debounce
if (gpio_get_level(PIN_WAKEUP_FROM_BUTTON) == 1) {
uint32_t start_tick = xTaskGetTickCount();
// Poll briefly while the button is pressed (100ms intervals)
while(gpio_get_level(PIN_WAKEUP_FROM_BUTTON) == 1) {
vTaskDelay(pdMS_TO_TICKS(100));
}
uint32_t duration_ms = (xTaskGetTickCount() - start_tick) * portTICK_PERIOD_MS;
if (duration_ms >= 500000) {
do_zigbee_reset();
} else if (duration_ms >= 100000) {
run_settings_portal();
} else {
//test zigbee send
if (px_zigbee_is_connected()) {
// send random values for testing
px_zigbee_send_flow((float)(rand() % 1000) / 10.0f); // 0.0 to 99.9 L/min
}
}
}
}
gpio_intr_enable(PIN_WAKEUP_FROM_BUTTON); // Re-enable interrupts from this pin after processing is done
}
}
Zigbee Code:
/* Zigbee signal handler callback */
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
{
ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}
void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
{
uint32_t *p_sg_p = signal_struct->p_app_signal;
esp_err_t err_status = signal_struct->esp_err_status;
esp_zb_app_signal_type_t sig_type = *p_sg_p;
switch (sig_type) {
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
ESP_LOGI(TAG, "Initialize Zigbee stack");
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
break;
case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:
if (err_status == ESP_OK) {
ESP_LOGI(TAG, "Device started up in%s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : " non");
if (esp_zb_bdb_is_factory_new()) {
ESP_LOGI(TAG, "Start network steering");
s_steering_retry_count = 0; // Reset retry counter
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
} else {
ESP_LOGI(TAG, "Device rebooted");
s_connected = true;
}
} else {
ESP_LOGW(TAG, "%s failed with status: %s, retrying", esp_zb_zdo_signal_to_string(sig_type),
esp_err_to_name(err_status));
esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb,
ESP_ZB_BDB_MODE_INITIALIZATION, 1000);
}
break;
case ESP_ZB_BDB_SIGNAL_STEERING:
if (err_status == ESP_OK) {
esp_zb_ieee_addr_t extended_pan_id;
esp_zb_get_extended_pan_id(extended_pan_id);
ESP_LOGI(TAG, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)",
extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4],
extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0],
esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address());
s_connected = true;
// wait for a while to allow coordinator device interview to complete before allowing sleep (if enabled)
s_steering_retry_count = 0; // Reset counter on success
ESP_LOGI(TAG, "Manual reporting active - coordinator reporting config ignored");
} else {
s_steering_retry_count++;
ESP_LOGW(TAG, "Network steering attempt %d/%d failed (status: %s)",
s_steering_retry_count, MAX_STEERING_RETRIES, esp_err_to_name(err_status));
if (s_steering_retry_count < MAX_STEERING_RETRIES) {
esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb,
ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
} else {
ESP_LOGE(TAG, "Failed to join network after %d attempts - giving up", MAX_STEERING_RETRIES);
}
}
break;
case ESP_ZB_COMMON_SIGNAL_CAN_SLEEP:
// Note: With esp_zb_sleep_enable(true), Zigbee automatically sleeps when idle
ESP_LOGI(TAG, "Zigbee can sleep (automatic sleep active)");
esp_zb_sleep_now();
break;
default:
ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s",
esp_zb_zdo_signal_to_string(sig_type), sig_type,
esp_err_to_name(err_status));
break;
}
}
esp_err_t px_zigbee_init(void)
{
ESP_LOGI(TAG, "Initializing PX Zigbee API");
esp_zb_platform_config_t config = {
.radio_config = {
.radio_mode = ZB_RADIO_MODE_NATIVE,
},
.host_config = {
.host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE,
},
};
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_zb_platform_config(&config));
return ESP_OK;
}
void px_zigbee_start(void *pv)
{
ESP_LOGI(TAG, "Starting Zigbee stack");
ESP_LOGI(TAG, "Zigbee sleep enabled");
esp_zb_sleep_enable(true);
/* Configure Zigbee network as End Device */
esp_zb_cfg_t zb_nwk_cfg = {
.esp_zb_role = ESP_ZB_DEVICE_TYPE_ED,
.install_code_policy = PX_ZB_INSTALLCODE_POLICY,
.nwk_cfg = {
.zed_cfg = {
.ed_timeout = PX_ZB_ED_AGING_TIMEOUT,
.keep_alive = PX_ZB_ED_KEEP_ALIVE, // 3000ms
},
},
};
ESP_LOGI(TAG, "Initializing Zigbee network config");
esp_zb_init(&zb_nwk_cfg);
ESP_LOGI(TAG, "Zigbee init done");
/* Register device with all endpoints and clusters */
ESP_LOGI(TAG, "Registering Zigbee device");
register_zigbee_device();
ESP_LOGI(TAG, "Device registration done");
/* Register action handler for Zigbee events */
ESP_LOGI(TAG, "Registering action handler");
esp_zb_core_action_handler_register(zb_action_handler);
esp_zb_set_primary_network_channel_set(ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK);
/* Start Zigbee stack */
ESP_LOGI(TAG, "Starting Zigbee stack main");
ESP_ERROR_CHECK(esp_zb_start(false));
ESP_LOGI(TAG, "Zigbee start done");
/* Set battery power descriptor must be at this position! */
ESP_LOGI(TAG, "Setting power descriptor");
esp_zb_set_node_descriptor_power_source(false);
esp_zb_af_node_power_desc_t power_desc = {
.current_power_mode = ESP_ZB_AF_NODE_POWER_MODE_COME_ON_PERIODICALLY,
.available_power_sources = ESP_ZB_AF_NODE_POWER_SOURCE_RECHARGEABLE_BATTERY,
.current_power_source = ESP_ZB_AF_NODE_POWER_SOURCE_RECHARGEABLE_BATTERY,
.current_power_source_level = ESP_ZB_AF_NODE_POWER_SOURCE_LEVEL_100_PERCENT,
};
esp_zb_set_node_power_descriptor(power_desc);
ESP_LOGI(TAG, "Power descriptor set");
// Enable Zigbee sleep with threshold
// Zigbee will automatically sleep when idle and wake up for communication
//esp_zb_sleep_set_threshold(20); // Sleep when idle for 20 milliseconds (default)
/* Enter main loop (blocks) */
ESP_LOGI(TAG, "Entering Zigbee main loop");
esp_zb_stack_main_loop();
}
To me it looks like the ESP is going too early into lightsleep. Also I think it would be better and faster when the ESP is not going to lightsleep during network steering and configuring.
Additional context.
Further Infos:
- I erased the Flash before every new test and removed the device from the Coordinator
- I attempted to call
esp_zb_sleep_enable(true)only after receiving theESP_ZB_BDB_SIGNAL_STEERING(statusESP_OK) signal to ensure the device remains awake during the handshake. However, this did not result in a stable sleep transition; it seems the sleep functionality might need to be initialized beforeesp_zb_init()to be properly registered by the stack. - To rule out interference or stack overflows, I increased the Zigbee_main task stack depth and disabled all auxiliary tasks (button logic). The behavior remained identical: steering only succeeds if sleep is disabled globally from the start.
Log:
ESP-ROM:esp32c6-20220919
Build:Sep 19 2022
rst:0x15 (USB_UART_HPSYS),boot:0xe (SPI_FAST_FLASH_BOOT)
Saved PC:0x40020872
--- 0x40020872: systimer_hal_get_counter_value in ROM
SPIWP:0xee
mode:DIO, clock div:2
load:0x40875730,len:0x1744
load:0x4086b910,len:0xf7c
load:0x4086e610,len:0x36fc
entry 0x4086b928
I (23) boot: ESP-IDF GIT-NOTFOUND 2nd stage bootloader
I (23) boot: compile time Feb 21 2026 13:14:56
I (24) boot: chip revision: v0.2
I (24) boot: efuse block revision: v0.3
I (27) boot.esp32c6: SPI Speed : 80MHz
I (31) boot.esp32c6: SPI Mode : DIO
I (34) boot.esp32c6: SPI Flash Size : 2MB
I (38) boot: Enabling RNG early entropy source...
I (43) boot: Partition Table:
I (45) boot: ## Label Usage Type ST Offset Length
I (52) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (58) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (65) boot: 2 factory factory app 00 00 00010000 00180000
I (71) boot: 3 zb_storage Unknown data 01 81 00190000 00004000
I (78) boot: 4 zb_fct Unknown data 01 81 00194000 00000400
I (84) boot: End of partition table
I (88) esp_image: segment 0: paddr=00010020 vaddr=42060020 size=1132ch ( 70444) map
I (108) esp_image: segment 1: paddr=00021354 vaddr=40800000 size=06cc4h ( 27844) load
I (115) esp_image: segment 2: paddr=00028020 vaddr=42000020 size=58018h (360472) map
I (184) esp_image: segment 3: paddr=00080040 vaddr=40806cc4 size=0de40h ( 56896) load
I (196) esp_image: segment 4: paddr=0008de88 vaddr=40814b10 size=023f0h ( 9200) load
I (199) esp_image: segment 5: paddr=00090280 vaddr=50000000 size=00090h ( 144) load
I (205) boot: Loaded app from partition at offset 0x10000
I (206) boot: Disabling RNG early entropy source...
I (222) cpu_start: Unicore app
I (230) cpu_start: Pro cpu start user code
I (230) cpu_start: cpu freq: 160000000 Hz
I (231) app_init: Application information:
I (231) app_init: Project name: ESP_main1
I (234) app_init: App version: 9bea364-dirty
I (239) app_init: Compile time: Feb 21 2026 13:25:10
I (244) app_init: ELF file SHA256: e5e571874...
I (248) app_init: ESP-IDF: v5.5.1
I (252) efuse_init: Min chip rev: v0.0
I (256) efuse_init: Max chip rev: v0.99
I (260) efuse_init: Chip rev: v0.2
I (264) heap_init: Initializing. RAM available for dynamic allocation:
I (270) heap_init: At 4081B290 len 00061380 (388 KiB): RAM
I (275) heap_init: At 4087C610 len 00002F54 (11 KiB): RAM
I (280) heap_init: At 50000090 len 00003F58 (15 KiB): RTCRAM
I (286) spi_flash: detected chip: generic
I (289) spi_flash: flash io: dio
W (292) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (305) sleep_gpio: Configure to isolate all GPIO pins in sleep state
I (311) sleep_gpio: Enable automatic switching of GPIO sleep configuration
I (318) sleep_clock: System Power, Clock and Reset sleep retention initialization
I (336) coexist: coex firmware version: b0bcc39
I (336) coexist: coexist rom version 5b8dcfa
I (337) main_task: Started on CPU0
I (337) main_task: Calling app_main()
I (339) PX_MAIN: System starting in Light-Sleep Mode...
I (344) pm: Frequency switching config: CPU_MAX: 160, APB_MAX: 160, APB_MIN: 160, Light sleep: ENABLED
I (354) PX_MAIN: GPIO wakeup and interrupts configured successfully
I (359) PX_ZIGBEE: Initializing ProjectX Zigbee API
I (369) PX_ZIGBEE: Starting Zigbee stack
I (369) PX_ZIGBEE: Zigbee sleep enabled
I (371) PX_ZIGBEE: Initializing Zigbee network config
I (377) phy_init: phy_version 341,a6c8fe6,Jul 30 2025,18:34:11
I (461) phy: libbtbb version: a945109, Jul 30 2025, 18:34:25
I (462) sleep_clock: Modem Power, Clock and Reset sleep retention initialization
I (464) PX_ZIGBEE: Zigbee init done
I (466) PX_ZIGBEE: Registering Zigbee device
I (470) PX_ZIGBEE: ======================================================================
I (478) PX_ZIGBEE: Creating Zigbee Device Structure
I (483) PX_ZIGBEE: ======================================================================
I (495) PX_ZIGBEE: ======================================================================
I (499) PX_ZIGBEE: Device Registration Complete!
I (503) PX_ZIGBEE: ======================================================================
I (511) PX_ZIGBEE: Device registration done
I (515) PX_ZIGBEE: Registering action handler
I (519) PX_ZIGBEE: Starting Zigbee stack main
I (526) PX_MAIN: Initialization finished. Entering Event-Loop.
I (527) PX_ZIGBEE: Zigbee start done
I (532) PX_ZIGBEE: Setting power descriptor
I (536) PX_ZIGBEE: Power descriptor set
I (539) PX_ZIGBEE: Entering Zigbee main loop
I (543) PX_ZIGBEE: ZDO signal: ZDO Config Ready (0x17), status: ESP_FAIL
I (550) PX_ZIGBEE: Initialize Zigbee stack
I (555) PX_ZIGBEE: Device started up in factory-reset mode
I (559) PX_ZIGBEE: Start network steering
W (2790) PX_ZIGBEE: Network steering attempt 1/30 failed (status: ESP_FAIL)
I (2791) PX_ZIGBEE: Zigbee can sleep (automatic sleep active)
--- Error: ClearCommError failed (PermissionError(13, 'Das Gerät erkennt den Befehl nicht.', None, 22))
--- Waiting for the device to reconnect..
W (6030) PX_ZIGBEE: Network steering attempt 2/30 failed (status: ESP_FAIL)
I (6030) PX_ZIGBEE: Zigbee can sleep (automatic sleep active)
Tested with Homeassistant and ZHA.
esp-idf: 5.5.1
esp-zboss-lib: 1.6.4
esp-zigbee-lib: 1.6.8