nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ZigBee problems with coordinator to subscribe the multi sensor

Good day.

I am currently developing with two NRF52840 DK boards, and I also have two NRF Dongles. On a dongle a sniffer for ZigBee. I am working with SDK 3.2. This is my first project with ZigBee, so I don't have much know-how yet.

My goal is to implement the coordinator as like CLI agent. So that it subscribes to the multi-sensor and receives data. Is so to speak an A to B communication.

With "zb_zdo_match_desc_req()" I get the short address and the endpoint of the sensor. Then with "zb_zdo_ieee_addr_req()" I get the long address  (EUI64) of the sensor. After that the "zb_zdo_bind_req()" request starts (Between coordinator and sensor) and in the callback function ("p_resp->status") this is confirmed successfully with ZB_ZDP_STATUS_SUCCESS. However, I only connect to the ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT cluster.

My questions:
1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

2) Is subscribing the sensor in the first step as below, correct?

// Step 8:
// Subscribe on Sensor
static void subscribe_device(zb_uint8_t param)
{
    zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
    configure_reporting_req_t          req;
    tsn_ctx_t                        * p_tsn_cli;
    zb_uint8_t                       * p_cmd_ptr;
    zb_ret_t                           zb_err_code;
    //zb_bool_t                          subscribe;
    zb_ieee_addr_t                     sensor_ieee_adr;

    NRF_LOG_INFO("----------------------------------------");
    NRF_LOG_INFO("Step 8: subscribe_device");


    req.profile_id   = ZB_AF_HA_PROFILE_ID;
    req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
    req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
    req.attr_type    = ZB_ZCL_ATTR_TYPE_S16;                //ZB_ZCL_ATTR_TYPE_16BIT;

    req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
    req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;

    req.remote_node.addr_short = m_device_ctx.bulb_params.short_address;
    req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
    req.remote_ep              = m_device_ctx.bulb_params.endpoint; 
    
    p_buf = ZB_GET_OUT_BUF();

    NRF_LOG_INFO("Configure Reporting");

    p_tsn_cli = get_free_tsn_ctx();
    if (!p_tsn_cli)
    {
        NRF_LOG_ERROR("Too many configure reporting requests");
        ZB_FREE_BUF(p_buf);
        return;
    }
   
    // Configure new tsn context.
    p_tsn_cli->taken = true;
    //p_tsn_cli->p_cli = p_cli;
    p_tsn_cli->tsn   = ZCL_CTX().seq_number;

    ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                    p_cmd_ptr, 
                                                    ZB_ZCL_ENABLE_DEFAULT_RESPONSE);

    ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                           req.attr_id, 
                                                           req.attr_type, 
                                                           req.interval_min, 
                                                           req.interval_max,
                                                           ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);

    ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                p_cmd_ptr,
                                                req.remote_node, 
                                                req.remote_addr_mode, 
                                                req.remote_ep, 
                                                m_device_ctx.co_params.endpoint, //CONTROLL_ENDPOINT
                                                req.profile_id, 
                                                req.cluster_id, 
                                                NULL);
    NRF_LOG_INFO("Report sended Waiting for Values");
    //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
    if (zb_err_code != RET_OK)
    {
        NRF_LOG_ERROR("Unable to schedule timeout timer");
        invalidate_ctx(p_tsn_cli);
    }
    NRF_LOG_INFO("End");
}

3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

My problems:
1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

Is there still something to change at the sensor, because there I have left everything as is.

My ep_handler_report Handler:

 
static zb_uint8_t ep_handler_report(zb_uint8_t param)
{
    NRF_LOG_INFO("Ep Handler Report");
    zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
    zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
    tsn_ctx_t           *  p_tsn_ctx;

    if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
    {
        NRF_LOG_INFO("print_attr");
        print_attr(p_cmd_info, param);
        ZB_FREE_BUF_BY_REF(param);
        return ZB_TRUE;
    }
    else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
    {
        // Find command context by ZCL sequence number.
        p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
        if (p_tsn_ctx != NULL)
        {

            NRF_LOG_WARNING("Unsubscribe cb");
            cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
            return ZB_TRUE;
        }
    }
    NRF_LOG_INFO("False Handler report");
    ZB_FREE_BUF_BY_REF(param);
    return ZB_FALSE;
}
  
/* Register callback for handling ZCL commands. */
ZB_AF_SET_ENDPOINT_HANDLER(m_device_ctx.bulb_params.endpoint, ep_handler_report);

The other functions as well as the output of the data I took from the CLI as well as from other discussions.

With the function "print_attr()" the data is output (Same function as with CLI), what am I doing wrong here with subscribe?

2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

I would also be glad if you could give me a quick rundown on the process for subscribing to devices. If you want the whole code, I can share it with pleasure.

Thanks in advance. Slight smile

With kind regards

Jonas T

Parents
  • Hi Jonas,

    1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

    If you want to receive attribute reports from both clusters then yes. You need to create a binding for each cluster you want to receive reports from, and you do that by sending individual bind requests to each cluster.

    2) Is subscribing the sensor in the first step as below, correct?

    It looks correct to me.

    3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

    No you do not need this callback. In the CLI example this callback is used to check the status of the Configure Reporting Response command received after sending the Configure Reporting command, to see if it was successful or not.

    Unsubscribe is for disabling reporting. In both the case where you subscribe and where you unsubscribe you send the same command to the remote device, the Configure Reporting command. The only differences between these two are the min and max interval fields of the command. When you subscribe these are set to valid values to configure periodic reporting, while unsubscribe will set min to 0x000F and max to 0xFFFF, indicating that it should not periodically report.

    1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

    Make sure to register the device context before registering the endpoint handler. For example:

    ZB_AF_REGISTER_DEVICE_CTX(&device_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(DEVICE_ENDPOINT, ep_handler_report);

    Also make sure you are using the correct endpoint. From your ZB_AF_SET_ENDPOINT_HANDLER it seems like you might be using the light switch example, since you are using m_device_ctx.bulb_params.endpoint. If that is the case, then the endpoint given by m_device_ctx.bulb_params.endpoint is the endpoint of the light bulb. The endpoint handler you register with ZB_AF_SET_ENDPOINT_HANDLER will handle ZCL packets incoming on the endpoint you use when you register it, so this endpoint must be an endpoint registered on the device, and it must be the same endpoint as used for the device context. So for the light switch you would have:

    ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(LIGHT_SWITCH_ENDPOINT, ep_handler_report);
    2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

    A beacon request is sent by a device wanting to join a network as a part of scanning for networks. Devices can do passive or active scans. In the case of active scans the device will send out a beacon request to try to discover networks on the channel. If there is a network, then nearby routers will send a beacon in response.

    Do you have any indication as to why the network crashes? If you upload a sniffer log of the issue as a pcap I can look at it and see if I can find what the issue might be.

    Best regards,

    Marte

Reply
  • Hi Jonas,

    1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

    If you want to receive attribute reports from both clusters then yes. You need to create a binding for each cluster you want to receive reports from, and you do that by sending individual bind requests to each cluster.

    2) Is subscribing the sensor in the first step as below, correct?

    It looks correct to me.

    3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

    No you do not need this callback. In the CLI example this callback is used to check the status of the Configure Reporting Response command received after sending the Configure Reporting command, to see if it was successful or not.

    Unsubscribe is for disabling reporting. In both the case where you subscribe and where you unsubscribe you send the same command to the remote device, the Configure Reporting command. The only differences between these two are the min and max interval fields of the command. When you subscribe these are set to valid values to configure periodic reporting, while unsubscribe will set min to 0x000F and max to 0xFFFF, indicating that it should not periodically report.

    1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

    Make sure to register the device context before registering the endpoint handler. For example:

    ZB_AF_REGISTER_DEVICE_CTX(&device_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(DEVICE_ENDPOINT, ep_handler_report);

    Also make sure you are using the correct endpoint. From your ZB_AF_SET_ENDPOINT_HANDLER it seems like you might be using the light switch example, since you are using m_device_ctx.bulb_params.endpoint. If that is the case, then the endpoint given by m_device_ctx.bulb_params.endpoint is the endpoint of the light bulb. The endpoint handler you register with ZB_AF_SET_ENDPOINT_HANDLER will handle ZCL packets incoming on the endpoint you use when you register it, so this endpoint must be an endpoint registered on the device, and it must be the same endpoint as used for the device context. So for the light switch you would have:

    ZB_AF_REGISTER_DEVICE_CTX(&dimmer_switch_ctx);
    ZB_AF_SET_ENDPOINT_HANDLER(LIGHT_SWITCH_ENDPOINT, ep_handler_report);
    2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

    A beacon request is sent by a device wanting to join a network as a part of scanning for networks. Devices can do passive or active scans. In the case of active scans the device will send out a beacon request to try to discover networks on the channel. If there is a network, then nearby routers will send a beacon in response.

    Do you have any indication as to why the network crashes? If you upload a sniffer log of the issue as a pcap I can look at it and see if I can find what the issue might be.

    Best regards,

    Marte

Children
  • Hi Marte,

    Thank you very much for answering my questions. I have included the light switch in the coordinator, so the lamp can be switched on and off (Is another project, but I have changed a lot here). That's why some variable names are still on the old name.

    Short question: the coordinator has the endpoint 0, right?

    The endpoint (Sensor) has the end point 10.

    Below I listed my "ZB_AF_REGISTER_DEVICE_CTX" and "ZB_AF_SET_ENDPOINT_HANDLER". Can you maybe take a look if this is so correct? Have about the same Configurations as the CLI.

    #define COORDINATOR_ENDPOINT     0
    
    // Variable structure
    typedef struct _coordintoor_bulb_parameter_
    {
        zb_uint8_t     endpoint;
        zb_uint16_t    short_address;
        zb_uint8_t       status;
        zb_ieee_addr_t long_address;
    } coordintoor_bulb_parameter;
    
    typedef struct _button_states_
    {
        zb_bool_t      button_pressed;
        zb_time_t      timestamp;
    } coordintoor_button_states;
    
    typedef struct _coordinator_params_
    {
        zb_uint8_t     endpoint;
        //zb_uint16_t   short_address;
        zb_ieee_addr_t long_address;
    } coordinator_params; 
                  
    typedef struct _coordinator_ctx_
    {
        coordintoor_bulb_parameter  bulb_params;
        coordintoor_button_states   button;
        coordinator_params          co_params;
    } coordinator_ctx;                  
    
    // Configurations
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CLUSTER_LIST(co_controll_cluster,
                                                   basic_attr_list,
                                                   identify_attr_list);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_EP(co_controll_ep,
                                        COORDINATOR_ENDPOINT,
                                        co_controll_cluster);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CTX(co_controll_ctx, co_controll_ep);
    
    
    // In the main
    
    /* Initialize application context structure. */
    UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(coordinator_ctx)));
    
    /* Set default bulb short_addr. */
    m_device_ctx.bulb_params.short_address = 0xFFFF;
    
    /* Register dimmer switch device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&co_controll_ctx);
    
    /* Register callback for handling ZCL commands. */
    ZB_AF_SET_ENDPOINT_HANDLER(COORDINATOR_ENDPOINT, ep_handler_report);
    
    /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
    zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);

    Because of the network crash, I have tested again. This only occurs after the binding request with the "ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT". Attached, I send you the sniffer data and the code that performs the binding. Maybe you will find a problem. The funny thing is that the sensor responds to the binding request, with Success, but after that the callback function is not called Disappointed (Look down below in the image sniffer data (marked yellow)).

    Still attached is my bind function as well as the corresponding callback function, maybe this helps you a bit. The long addresses are passed correctly after own checks (NRF_LOG_INFO...).

    // STEP 7:
    
    static zb_void_t zb_bind_callback(zb_uint8_t param)
    {
        NRF_LOG_INFO("Bind Callback");
        zb_buf_t           * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        m_device_ctx.bulb_params.status = p_resp->status; 
    
        if (m_device_ctx.bulb_params.status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Step 7: Bind successfully on Target: 0x%04x, Endpoint: %d", m_device_ctx.bulb_params.short_address, m_device_ctx.bulb_params.endpoint);
            ZB_FREE_BUF_BY_REF(param);	
            //subscribe_device(param);
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
    }
    
    // STEP 6:
    
    static zb_void_t bind_device(zb_uint8_t param)
    {   
        zb_buf_t                  * p_buf  = ZB_BUF_FROM_REF(param);  // Resolve buffer number to buffer address 
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        if (!p_buf)
        {
            NRF_LOG_ERROR("failed to execute command (buf alloc failed)");
            return;
        }
    
        p_req  = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 6: Try to bind");
    
        //ZB_MEMCPY(&p_req->src_address,           &m_device_ctx.bulb_params.long_address, sizeof(zb_ieee_addr_t));   //ieee address of sensor
        //ZB_MEMCPY(&p_req->dst_address.addr_long, &dst_ieee_addr,                         sizeof(zb_ieee_addr_t));   //ieee address of coordinator
    
        for (uint8_t i=0; i<8; i++)
        {
            p_req->src_address[i] = m_device_ctx.bulb_params.long_address[i];     //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
        }
    
        p_req->dst_addr_mode = ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
    
        p_req->src_endp      = m_device_ctx.bulb_params.endpoint;                 //endpoint of sensor
        p_req->dst_endp      = COORDINATOR_ENDPOINT;                              //endpoint of coordinator "0"
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;                //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.bulb_params.short_address;            //short address of sensor
    
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback);
    
        NRF_LOG_INFO("tsn: %d", tsn);
    
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
    	    return;
        }
        return;
    }

    Sniffer Data:

    If I do not call the "bind_device" function, the sensor remains connected in the network. This means that it should be the "bind_device" function that is the problem.

    Thanks again and best regards,

    Jonas

  • Hi Jonas,

    Jonas T said:
    Short question: the coordinator has the endpoint 0, right?

    You cannot use endpoint 0 for your application, as it is reserved for the data interface to the ZDO. 

    Jonas T said:
    Below I listed my "ZB_AF_REGISTER_DEVICE_CTX" and "ZB_AF_SET_ENDPOINT_HANDLER". Can you maybe take a look if this is so correct?

    It looks correct, just make sure to change COORDINATOR_ENDPOINT to a valid endpoint (1-254).

    Jonas T said:
    Because of the network crash, I have tested again. This only occurs after the binding request with the "ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT". Attached, I send you the sniffer data and the code that performs the binding. Maybe you will find a problem.

    From your sniffer log and what you say about the bind callback not being called it seems like the coordinator stops working either right after sending the bind request or immediately when it receives the response but before it is able go into the callback function. The issue might be related to your coordinator endpoint, since you are creating a binding on an endpoint that is reserved and should not be used in the application. You should change COORDINATOR_ENDPOINT to something else and see if that fixes the issue. Other than that I do not see any obvious issues with your bind request and callback. If you are still seing the problem after changing the endpoint value you can upload your project here and I can test it on my side.

    Best regards,

    Marte

  • Hi Marte,

    Thank you very much for response. I did the coordinator number wrong and have now changed it. Thank you for the advice. Slight smile However, unfortunately, the error can not be fixed Hushed. I also copied the main and loaded into a new ZigBee light example (light_coordinator [ZigBee_3_2\examples\zigbee\light_control\light_coordinator"). But again the same error came out. Slight frown

    The aim of the project is to read out the multi sensor with a coordinator and to output it on the interface (e.g. uart, display...).

    But I'll try to get only the temperature values from the sensor, later the pressure will follow.

    I have now enclosed the entire project folder for you and will point out the locations. Additionally I have attached the Main File to them again.

    All code has been implemented in the "main.c" file. All functions are listed below and can be found via the project search in the main (Would recommend). They have also been labeled and numbered in large ASCII text. I then also adjusted the naming of some variables, as well as from Coordinator to "Sensor logger".

    Function names for the search:
    Signal Handler: "zboss_signal_handler". (Line 1039)

    1) Send a match request: "send_match_desc_req" (Line 968)
    Callback function: "cmd_zb_match_desc_cb"

    2) Long address request: "zb_ieee_addr_req"  (Line 894)
    Callback function: "ieee_addr_cb"

    3) Send bind request: "bind_device" (Line 779)
    Callback function: "zb_bind_callback"

    4) Subscribe function: "subscribe_device" (Line 670)

    Do I also make a little bit of a mix-up with the buffers? If so, do you have any tips or internet sites?

    Now I wish you still good luck with testing and thank you again. Hope everything works. Ok hand

    With kind regards

    Jonas

  • Hi Jonas,

    Thanks for the detailed and clear explanation and code! Makes it much easier for us to debug projects and understand what is actually going on Slight smile

    I have started looking at your issue, and it seems to be buffer leak. The device gets a hard fault in zb_get_buf.

    When I commented out p_buf = ZB_GET_OUT_BUF(); in bind_device(), as well as the if statement for the buffer (lines 793-798), the device continued to run after the binding, and ran for about a minute before stopping. After also commenting out = ZB_BUF_FROM_REF(param); on line 677 in subscribe_device() so that the line was only zb_buf_t * p_buf; it ran for longer, about 4 minutes. All three times it crashed because of hard fault in zb_get_buf, and I suspect that is because it is not able to allocate a new buffer because they are all used. I have not had the chance to go through the entire project and find all possible problems yet, but I see that you are allocating a lot of buffers and scheduling alarms, so I would suggest starting by looking at this, so the places you use ZB_GET_OUT_BUF, ZB_BUF_FROM_REF, ZB_SCHEDULE_ALARM, etc. 

    When the device was running it worked as expected, successfully creating a binding, receiving attribute reports and calling the endpoint handler, so that part works as it should until the hard fault.

    I will keep looking into the problem tomorrow.

    Jonas T said:
    Do I also make a little bit of a mix-up with the buffers? If so, do you have any tips or internet sites?

    ZB_GET_OUT_BUF is used to allocate a new out buffer, while ZB_BUF_FROM_REF is a helper function to get a buffer by using its reference, and is used instead of buffer pointers. You can read more about this in Zigbee stack memory management subsystem.

    Best regards,

    Marte

  • Hi Marte,

    It works for me even after commenting out the lines, thank you very much. I will also still look around the problem, if I can get it to work Rolling eyes. Yes, the network crashes after about 4 min.
    Then I will hear from you again regarding last answer. Thumbsup

    Again quick question: For me the Attributes report works even if I don't call Subscribe function, is that normal? 

    Thanks a lot and best regards
    Jonas T

Related