zb_zdo_pim_start_turbo_poll_continuous() not working

I am developing a Zigbee sensor device based on the nRF52840. I have based my firmware on the "Thingy:53: Zigbee weather station" sample. This means it is a Sleepy End Device. To reduce power consumption, I increased the long poll interval to 60s using zb_zdo_pim_set_long_poll_interval(). This works so far, with the disadvantage that it is practically impossible to send any commands (configure reporting, identify, ...) to the device from the coordinator, which only keeps outgoing packets for around 10s before timing out.

To resolve this, I intend to use the button on the device to poll the coordinator manually. From the SDK documentation I inferred that zb_zdo_pim_start_turbo_poll_continuous() should do what I want, i.e. polling the coordinator manually for a few seconds. However, the function call doesn't seem to do anything. Using a Zigbee sniffer in Wireshark I see no packets of any kind being sent upon pressing the button and calling the function.

The Turbo Poll feature is enabled: After joining the network, the ED sends multiple polling packets in increasing time intervals, which I assume to be determined by the "Turbo Poll adaptive algorithm". If I explicitly disable Turbo Poll using zb_zdo_pim_permit_turbo_poll(ZB_FALSE), these multiple polling packets don't happen. Calling zb_zdo_pim_start_turbo_poll_continuous() in the button handler doesn't do anything either way.

This is the part of the documentation that I am referring to : https://developer.nordicsemi.com/nRF_Connect_SDK/doc/zboss/3.11.4.0/zigbee_prog_principles.html#zigbee_data_polling_mechanism

Did I misunderstand what zb_zdo_pim_start_turbo_poll_continuous() is supposed to do? I expected that simply calling this function once sends multiple polling packets over the specified time. Are there any other prerequisites I need to ensure, such as disabling ZBOSS sleep or explicitely sending a packet?

  • Thanks Marte. Yes, now that you point it out I can confirm that I see the same behaviour.

    So I thought the solution is simple, I could just decrease the long poll interval temporarily to a short value, such as 1000ms. But, sadly, even zb_zdo_pim_set_long_poll_interval() only takes effect upon the next long poll event. So it takes up to 60s for the next poll event to happen, but then it continues polling every 1000ms.

    My intended way of operation was a regular long poll interval of 60s or longer, but when the user presses the button of the device, it would immediately start polling with a high rate for about 10s. Afterwards it should go back to the slow long poll rate of before. Do you have a solution to achieve this specific behaviour?

  • Hi,

    There is no way to directly increase the polling rate temporarily other than when waiting for a response or a fragmented message as with turbo poll.

    One option is for the device to send a simple Zigbee command to the parent when the user presses the button. This will make the device poll the parent, and the parent can send the packets it has been keeping for the device. It can be something as simple as an Active Endpoint Request.

    Best regards,
    Marte

  • Thank you Marte. With your help I was able to implement the desired behaviour. I didn't quite do it as you suggested but similar: When the button is pressed, a sensor measurement is done and the relevant attributes are set. As a result the device reports the values back and also receives any pending messages from the network.

    The only issue occurs when the measured values are not different enough from the previous ones to cause attribute reporting. My workaround is to set the ZB_ZCL_REPORT_IS_FIRST flag of the relevant zb_zcl_reporting_info_t structs before calling zb_zcl_set_attr_val(). This causes the attributes to be reported in any case. I'll leave the code here in case anybody else has a similar problem in the future:

    /**
     * Force the specified attribute to be reported the next time it is set to any value.
     * 
     * This is accomplished by setting the reporting_info's REPORT_IS_FIRST flag.
     * 
     * Adapted from zb_zcl_set_attr_val() and zb_zcl_mark_attr_for_reporting_manuf().
     */
    zb_zcl_status_t force_report_attr_on_next_update(zb_uint8_t ep, zb_uint16_t cluster_id, zb_uint8_t cluster_role, zb_uint16_t attr_id) {
    	zb_zcl_status_t status = ZB_ZCL_STATUS_FAIL;
    	zb_zcl_attr_t *attr_desc;
    	zb_zcl_reporting_info_t *rep_info;
    
    	attr_desc = zb_zcl_get_attr_desc_a(ep, cluster_id, cluster_role, attr_id);
    
    	if (attr_desc != NULL) {
    		if (ZB_ZCL_IS_ATTR_REPORTABLE(attr_desc)) {
    			rep_info = zb_zcl_find_reporting_info_manuf(ep, cluster_id, cluster_role, attr_id, attr_desc->manuf_code);
    			if (rep_info != NULL) {
    				ZB_ZCL_SET_REPORTING_FLAG(rep_info, ZB_ZCL_REPORT_IS_FIRST);
    
    				status = ZB_ZCL_STATUS_SUCCESS;
    			} else {
    				status = ZB_ZCL_STATUS_NOT_FOUND;
    			}
    		} else {
    			status = ZB_ZCL_STATUS_UNREPORTABLE_ATTRIB;
    		}
    	} else {
    		status = ZB_ZCL_STATUS_NOT_FOUND;
    	}
    
    	return status;
    }

Related