How to reduce zigbee power consumption when endpoint is searching network

We have a multiprotocol project running BLE and Zigbee Stacks. The device always operate on BLE, but Zigbee is optional. The project is developed using NCS with zephyr revision v2.4.99-ncs2. Zigbee can be enabled or disabled writing to a BLE characteristic. The device is configured as a Zigbee Endpoint

Zigbee stack is started with those lines of code:

	zb_af_register_device_ctx(&device_context);

	zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
	zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
	zb_set_rx_on_when_idle(ZB_FALSE);

	zigbee_enable();

When zigbee stack is searching network, the device is consuming around 15 mA, and after successful steering it lows down to 100 uA. If Zigbee is enabled, consumption is OK, but when Zigbee is disabled, and no network is available, the device keeps consuming 15 mA forever.

My questions are:

¿How can I disable the Zigbee stack on runtime, and avoid the consumption part due to zigbee functions?

alternatively

¿Is there a way to simulate a network join, without having a real network, so that the Zigbee EP thinks it is connected and the consumption keeps on 100 uA?

Even if we decide not to execute zigbee_enable at start up, the fact of having CONFIG_ZIGBEE=y consumes around 1 mA. So that not enabling zigbee at start up, is not an option.

Any help will be appreciated, thanks,

Jordi

  • Hi Jordi,

    If Zigbee is enabled, consumption is OK, but when Zigbee is disabled, and no network is available, the device keeps consuming 15 mA forever.

    The current consumption should not be so high, which leads me to believe there is some issue with how you disable Zigbee. The Zigbee current consumption should be in lower µA-levels if its idling or is done with searching/establishing networks, which means that it might still be in a phase where it tries to establish and search for a network.. Could you show/add code for how you disable Zigbee?

    ¿How can I disable the Zigbee stack on runtime, and avoid the consumption part due to zigbee functions?

    An option you could investigate is to check multiprotocol support in NCS with this Zigbee sample that supports enabling of multiprotocol support (and for some more reading multiprotocol support in nRF5 SDK). This should, to my knowledge, allow you to time slice when you allow which of the protocols to use the radio.  

    Let me know about how you disable Zigbee and if any of this helps at all!

    Kind regards,
    Andreas

  • Hi Andreas,

    First of all, sorry for the late response.

    As for your question of how I disable zigbee, indeed, I have tried to execute many functions trying to disable it.  As there is no equivalent function to zigbee_enable(), I have tried zb_bdb_reset_via_local_action(0), zdo_mgmt_leave_req(0). I have also tried to execute zb_sleep_now() at a 2 second interval, and finally as in the light_switch sample, I have tried zigbee_configure_sleepy_behavior(true), but the least I get when is around 2 mA. (Remember consumption is ok when steering is successful, this behavior only occurs when no zigbee network is found)

    With the power profiler I see consumption is 17mA until second 42, when it decreases to 170 uA just for 2 seconds and then it begins again at 17 mA. This 42 seconds coincides at the time when steering is not successful, as you can see in attached log. If we managed to stabilized consumption to 170 uA after not successfully steering, that would be ok.

    00> [00:00:00.435,821] <inf> ieee802154_nrf5: nRF5 802154 radio initialized
    00> *** Booting Zephyr OS build v2.4.99-ncs2-1  ***
    00> 
    00> [00:00:00.909,973] <dbg> wbolt.WBolt: Zigbee is enabled
    00> [00:00:00.910,064] <inf> sdc_hci_driver: SoftDevice Controller build revision: 
    00>                                          d9 e2 43 71 3b 2d c0 15  55 e1 1d c8 99 75 01 7a |..Cq;-.. U....u.z
    00>                                          62 85 8d 0a                                      |b...             
    00> [00:00:00.914,520] <dbg> BluetoothAdvertising.setDeviceName: Device name is wBolt FA9B8F6E371B
    00> 
    00> [00:00:00.922,912] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 16
    00> [00:00:00.922,943] <inf> zigbee_app_utils: Production configuration is not present or invalid (status: -1)
    00> [00:00:00.923,095] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 1
    00> [00:00:00.923,095] <inf> zigbee_app_utils: Zigbee stack initialized
    00> [00:00:01.187,225] <inf> spi_nrfx_spim: CS c0m
    00> [00:00:10.909,942] <dbg> ZigbeeDeviceContext.joinedTimeout: ...
    00> [00:00:10.909,942] <inf> zigbee_app_utils: Enabled sleepy end device behavior.
    00> [00:00:10.909,942] <inf> ram_pwrdn: RAM power off unsupported.
    00> [00:00:43.126,403] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 7
    00> [00:00:43.126,434] <inf> zigbee_app_utils: Network steering was not successful (status: -1)
    00> [00:00:43.126,739] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:00:43.126,953] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:01:26.041,259] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 7
    00> [00:01:26.041,259] <inf> zigbee_app_utils: Network steering was not successful (status: -1)
    00> [00:01:26.041,595] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:01:26.041,778] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:02:10.955,688] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 7
    00> [00:02:10.955,688] <inf> zigbee_app_utils: Network steering was not successful (status: -1)
    00> [00:02:10.955,993] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:02:10.956,207] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:02:59.863,342] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 7
    00> [00:02:59.863,342] <inf> zigbee_app_utils: Network steering was not successful (status: -1)
    00> [00:02:59.863,647] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:02:59.863,861] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:03:21.374,328] <inf> zigbee_app_utils: Network rejoin procedure stopped as scheduled.
    00> [00:03:56.777,313] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 7
    00> [00:03:56.777,313] <inf> zigbee_app_utils: Network steering was not successful (status: -1)
    00> [00:03:56.777,465] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:03:56.777,618] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:04:06.776,855] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:04:16.776,092] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:04:26.775,329] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:04:36.774,566] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15
    00> [00:04:46.773,803] <dbg> ZigbeeDeviceContext.zboss_signal_handler: sig = 15

  • Hi,

    No worries about the response time. We get notified when a reply comes in on our open tickets.

    Allright, so I see you've tried a couple of functions to disable the Zigbee network and none of them works as intended, which is as expected if we take a closer look on what these functions do. 

    • zb_bdb_reset_via_local_action(0): In short terms, what this function does is to factory reset the Zigbee stack and sends the ZB_ZDO_SIGNAL_LEAVE to the network, and leaving the network. It does not disable the Zigbee. 
    • zdo_mgmt_leave_req(): This function sends a "management leave request" to a device and asks it to leave the network. It can be used to ask other devices to leave the network or send it to itself and leave the network itself. 
    • zb_sleep_now(): As far as I know this function puts the network to sleep on command, but it whenever it gets interrupted by any routines or tasks to do, the system goes out of sleep. It is only usable in a end device such as a light switch, which does not continually have tasks to do (unless it is toggled all the time). 

    What all these 3 functions have in common, is that if you try to leave the network in any manner, the first action that happens after this is done is that the device starts looking for a network again, leaving you with the power spikes whenever this process starts. 

    You're right that there are no equivalent function to zigbee_enable() in the shape of a "zigbee_disable()", which is why multiprotocol support in NCS with this Zigbee sample that supports enabling of multiprotocol support is the proper way to implement it. Over time, the power consumption caused by the action of searching and joining a network becomes far larger than to properly implement a time sliced multi-protocol application. Doing it this way you may take advantage of the functionality that negotiates timeslots for the 802.15.4 radio driver and ensure that the various protocols have allocated enough time to the tasks required by them such as discovering, joining, and performing other various tasks in the queue before going to sleep and being awoken. 

    Feel free to follow up with more questions and let me know if this clarifies anything for you!

    Kind regards,
    andreas

  • Hi Andreas,

    Thanks for your answer. I attached my code here for the zboss_signal_handler and for the function start, that starts the zigbee stack. You can observe is like in the example Multiprotocol Light Switch . The Sleepy End Device behavior is enabled with the function zb_set_rx_on_when_idle(ZB_FALSE):

    void zboss_signal_handler(zb_bufid_t bufid)
    {
    	ZigbeeDeviceContext* instance = ZigbeeDeviceContext::getInstance();
    
    	zb_zdo_app_signal_hdr_t* p_sg_p = nullptr;
    	zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &p_sg_p);
    	zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
    
    	LOG_DBG("sig = %d", sig);
    
    	ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
    
    	if(sig == ZB_BDB_SIGNAL_STEERING || sig == ZB_BDB_SIGNAL_DEVICE_REBOOT) {
    		if(status == RET_OK) {
    			instance->joinedSuccessful();
    		}
    	} else if(sig == ZB_COMMON_SIGNAL_CAN_SLEEP) {
    		if(instance->isJoined() == true) {
    			zb_sleep_now();
    		}
    	}
    	/* All callbacks should either reuse or free passed buffers.
    	 * If bufid == 0, the buffer is invalid (not passed).
    	 */
    	if(bufid) {
    		zb_buf_free(bufid);
    	}
    }
    
    void ZigbeeDeviceContext::start()
    {
    	ZB_ZCL_REGISTER_DEVICE_CB(commandHandler);
    
    	if(endpoints.empty() == false) {
    		device_context.ep_count = endpoints.size();
    		device_context.ep_desc_list = new zb_af_endpoint_desc_t*[device_context.ep_count];
    		int i = 0;
    		for(const auto& endpoint: endpoints) {
    			device_context.ep_desc_list[i] = endpoint.second->getDescriptor();
    			i++;
    		}
    	}
    
    	zb_af_register_device_ctx(&device_context);
    
    	zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
    	zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    	zb_set_rx_on_when_idle(ZB_FALSE);
    
    	zigbee_enable();
    }
    

    Now, I have just discovered than if I comment line 330 of file zigbee_app_utils.c:

    // 				start_network_rejoin();
    

    The system behaves as desired, that is, consumption is high 17mA for 40 seconds, while end device is trying to join network, and is low 150 uA, after those 40 seconds.

    So, my conclusion is that the fact that the end device is continuously trying to join to a zigbee network is the responsible for high consumption.

    I don't like the solution of commenting line 330, because zigbee_app_utils.c belongs to the SDK. So, do you think, there is another way of avoiding a continuous network rejoin try (change CONFIG, call to a function, ... any idea?)

    Thanks,

    Jordi

  • Hi,

    Jorcis said:
    So, my conclusion is that the fact that the end device is continuously trying to join to a zigbee network is the responsible for high consumption.

    This is correct.

    Jorcis said:
    I don't like the solution of commenting line 330, because zigbee_app_utils.c belongs to the SDK

    I also agree with this. It is possible to edit and change the SDK files as you see fit, and some scenarios may require developers to do it, but personally I like the mentality of trying to fix it from the top down first, rather than changing the foundation through personal, customized hacks.

    Jorcis said:
    So, do you think, there is another way of avoiding a continuous network rejoin try (change CONFIG, call to a function, ... any idea?)

    One option you could implement to get this behavior is to override the zigbee_default_signal_handler function, which gets called within "void zboss_signal_handler(...)" in the light switch sample, line 439. If you create something that overrides the error_check that calls the default signal handler, it should avoid going through the motions of searching for and rejoining a network. I don't have a sample that illustrates this, but I believe it should be a relatively simple change to implement.

    Let me know if this works out for you!


    Kind regards,
    Andreas

Related