This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Thermostat cluster enable issue

Hi All,

I am developing product using nRF52840 and SDK nRF5_SDK_for_Thread_and_Zigbee_v3.0.0_d310e71.

This product is basically, using the Thermostat cluster and Zigbee protocol to communicate with the Zigbee gateway.

So, I referred light_bulb example and followed steps to enable "Thermostat cluster and attributes".

I have included the respective files also but I am unable to execute the below callback function case statement,

static zb_void_t zcl_device_cb(zb_uint8_t param)
{
    zb_uint8_t                       cluster_id;
    zb_uint8_t                       attr_id;
    zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
    zb_zcl_device_callback_param_t * p_device_cb_param =
                     ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);

    NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);

    /* Set default response value. */
    p_device_cb_param->status = RET_OK;

    switch (p_device_cb_param->device_cb_id)
    {
        case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
            cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
            attr_id    = p_device_cb_param->cb_param.set_attr_value_param.attr_id;

            if (cluster_id == ZB_ZCL_CLUSTER_ID_THERMOSTAT)
            {
                uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;

                NRF_LOG_INFO("thermostat local temperature: %d", value);
                if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID)
                {
                    local_temperature_value(value);
                }
            }
            else
            {
                /* Other clusters can be processed here */
                NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
            }
        break;

        default:
            p_device_cb_param->status = RET_ERROR;
            break;
    }

    NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
}

Also, I am attaching code for reference please let me know what else I forgot to enable the functions. It is urgent for me to solve this issue.

Radiator_nRF_v0.9.0.zip

And, with these attributes, for some of the commands, I need to implement custom attributes so if you share how to add custom attributes to this cluster.

Thanks in advance.

Regards,

Rohit R

Parents
  • Hi Rohit,

    I am not sure what you are trying to do in your callback. The thermostat cluster does not receive or send any commands related to the local temperature attribute, so you should not use the callback function for ZCL commands for this. Instead, you should read the attribute using either read attribute request command, or attribute reporting, which are explained here and here. You can also read about these commands in the Zigbee cluster library specification. The read attributes request command should be sent by the other device, so the gateway in your case. Same goes for configuring attribute reporting. 

    The implementation of the Pressure Measurement cluster in the SDK can be used to see how to implement attributes, both zb_zcl_pressure_measurement.h and zb_zcl_pressure_measurement.c, which can be found in components/zigbee/pressure_cluster/. You must add the attribute identifiers (ZB_ZCL_ATTR_NAME_VALUE_ID), implement the attributes according to your specification (for example set max value if they have that etc.), set the attribute description (ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_NAME_ID), declare your attribute list (ZB_ZCL_DECLARE_NAME_ATTRIB_LIST). All of this can be found in the Pressure Measurement cluster implementation. You must also remember to add it to your attribute list that you declare in main.c. Since you are using custom clusters, you cannot use ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST to declare the attributes, but you can use ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_CUSTOM or something similar instead.

    Best regards,

    Marte

  • Hi Marte,

    Thanks for the feedback,

    This means, local temperature is just a read attribute and we can not use it in the callback function. We need to create other function where we can just read only. Correct?

    Since you are using custom clusters, you cannot use ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST to declare the attributes, but you can use ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_CUSTOM or something similar instead.

    - I didn't get this statement. I have not yet designed any custom attributes. I want to design custom for that I need how to enable them. Which Id's are aviable? And in which file do we need declare them?

    - And pressure_measurement is custom file ?

    Thanks and Regards

    Rohit R

  • Hi,

    Any update to this?

    Why I am not able to see my IDs?

    Thanks and Regards

    Rohit R

  • Hi Rohit,

    I have been working on this today. Since I was unable to build the project you attached in your other case because of a missing file, I used the project I created earlier instead, and tried to create a custom cluster with a custom attribute.

    I created the files zb_zcl_custom_thermostat.h and zb_zcl_custom_thermostat.c for the cluster itself. This is a very bare bones implementation of the cluster, with only one attribute, but I hope it will still be of help. It should contain the necessary parts for a custom cluster. I used one of the attributes you mentioned in your other case, ZB_ZCL_ATTR_THERMOSTAT_VALVE_ID. Since I did not know anything specific about this attribute, I just chose something regarding attribute type and accesses, as well as the default value, so I would be able to test it. I did not implement any functionality in the cluster specific functions check value and write attribute hook. They are there for you to use, but they are mostly empty.

    Since you will be using a custom cluster, you cannot use the regular HA thermostat device anymore. Therefore, I also added a file zb_custom_ha_thermostat.h for a custom HA thermostat with the custom cluster added there. I also cleaned up the main.c file a bit and moved parts of it into the custom ha thermostat device file, as a lot of the code made more sense to have in this file. So a lot of the declarations and such at the beginning of the main.c file I attached earlier has been moved. I also just simulated some value for the thermostat valve attribute to test it.

    I have defined a cluster ID for the custom cluster and a profile ID for the custom HA thermostat device. These can both be changed to something else, as long as the IDs are not used by any other clusters or profiles, and the cluster ID must be in the range 0xfc00 – 0xffff, and the profile ID 0xc000 – 0xffff.

    I cannot say if this will work in your Gateway GUI or not. I did have some problems with attribute reporting, which does not work as expected, but I have not been able to figure out what the issue is yet. However, besides attribute reporting the custom cluster seemed to work as it is supposed to. Again I tested this using the CLI Agent example. I was able to use match descriptor (zdo match_desc) to find the device using the cluster ID of the custom cluster, and I was able to create a binding between the endpoints of the nodes (zdo bind on), also using the cluster ID. I was also able to read the value of the attribute ZB_ZCL_ATTR_THERMOSTAT_VALVE_ID by sending an read attributes request (zcl attr read). So even though there is a problem with attribute reporting, other nodes should be able to see and find this one and the custom cluster, as well as get the value of the attributes of the custom cluster.

    custom_ha_thermostat.zip

    Best regards,

    Marte

  • Hi Marte,

    Sorry for the late reply,

    I was out of station for few days,

    Thank you for the file and details.

    I have compared as well as tried your files into my project. But still, the result is the same. I am not able to see my Id in GUI.

    I have one dev-kit so can not try using CLI example but the gateway which I am using shows all the ID. I have tried with different examples in that I can see that GUI shows all ID.

    Also, along with this, I tried to add extra IDs, referred to the basic file to add. But still the result same. I have modified the SDK thermostat ha file. And that's fine for me. I am attaching the code for reference.

    I have added this in the light_bulb example file. Code built without any error but why IDs are not enabling understanding.

    Please check the code. I am using SDK 3.0 Zigbee and thread. And as per Zigbee cluster specification, it says "0x400 -0xfff Reserved for vendor-specific attributes".

    Radiator_nRF-v0.9.2.zip

    Thanks and Regards,

    Rohit R

  • Hi Rohit,

    It is difficult to say why it is not working with the Gateway GUI you are using, as I am not familiar with it and I do not know how it works.

    I will look at your project to see if I can figure out what the issue is and come back to you.

    Best regards,

    Marte

  • Hi Marte,

    I have tried one more method to add the required cluster into the project,

    Required cluster for the project,

    1. Basic

    2. Identity

    3. Power Configuration

    4. Thermostat

    5. Time

    6. OTAU

    I have referred multi_sensor example and created a separate custom1_thermosatat.h file like how they created it for the sensor.

    Tried to add the above-mentioned cluster. Currently in code added Basic, Identity, Power Configuration, thermostat, and Time.

    As I am stuck for custom attribute ID for the thermostat. Thought lets finish the power and time cluster part first. And waiting for your response.

    So, enabled both in code and just initialized the power id values in init() functions. As you can see in the attached code.

    With GUI I am able to see that, My cluster is added as per the .h file created. So next step I planned to initialize power's "Remaining percentage", "Voltage", "Size" and "Quantity".But I am not able to see those ids are highlighted.

    Attached is the image for reference (image of power config)

    For the Basic cluster, I have followed the same steps and you can see that whatever I initialized for the basic cluster I am able to see in GUI. Attached is the image for basic.

    (Image for Basic)

    Can you please help me with what else should be enabled here for power and other clusters?

    Code,

    Radiator_nRF_v0.9.3.zip

    Thanks and Regards

    Rohit R

Reply
  • Hi Marte,

    I have tried one more method to add the required cluster into the project,

    Required cluster for the project,

    1. Basic

    2. Identity

    3. Power Configuration

    4. Thermostat

    5. Time

    6. OTAU

    I have referred multi_sensor example and created a separate custom1_thermosatat.h file like how they created it for the sensor.

    Tried to add the above-mentioned cluster. Currently in code added Basic, Identity, Power Configuration, thermostat, and Time.

    As I am stuck for custom attribute ID for the thermostat. Thought lets finish the power and time cluster part first. And waiting for your response.

    So, enabled both in code and just initialized the power id values in init() functions. As you can see in the attached code.

    With GUI I am able to see that, My cluster is added as per the .h file created. So next step I planned to initialize power's "Remaining percentage", "Voltage", "Size" and "Quantity".But I am not able to see those ids are highlighted.

    Attached is the image for reference (image of power config)

    For the Basic cluster, I have followed the same steps and you can see that whatever I initialized for the basic cluster I am able to see in GUI. Attached is the image for basic.

    (Image for Basic)

    Can you please help me with what else should be enabled here for power and other clusters?

    Code,

    Radiator_nRF_v0.9.3.zip

    Thanks and Regards

    Rohit R

Children
  • Hi Marte,

    Any update on my queries?

    Also, I would like to know to send read request from EndPoint device to Coordinator device (nRF to Gateway).

    For my project, time and custom cluster I required send read request function. I have followed this explanation which you have shared previously. 

    As for ZB_ZCL_GENRAL_SEND_READ_ATTR_REQ, the different parameters are:

    • zcl_cmd_buf - buffer to place data to
    • cmd_ptr - pointer to the memory area after the command data end
    • addr - address to send packet to
    • dst_addr_mode - addressing mode
    • dst_ep - destination endpoint
    • ep - sending endpoint
    • ZB_AF_HA_PROFILE_ID - profile identifier
    • ZB_ZCL_CLUSTER_ID_THERMOSTAT - cluster identifier
    • cb (here NULL) - callback for getting command send status

    But few points are not clear to me,

    addr - how to get coordinator address in endpoint

    dst_addr_mode - in which file I get address mode

    dst-ep - is this coordinator end point ? if yes how to read this ?

    ep- this means my endpoint device id - (example THERMOSTAT_EP)

    cb - it should be NULL or we can give function to read data?

    And in the link it not mentioned to enable these function which file to be included? I had searched in SDK but it says no matching function?

    Hope, I get quick reply on this.

    Thanks and Regards,

    Rohit R.

  • Hi Rohit,

    I am sorry for the delayed answer. I have been looking at and testing the latest project you attached, v0.9.3, and I am still working on it. I have not figured out a solution yet, but I will answer your questions and update you on what I have found so far.

    I am still testing with the CLI example, since that is the best alternative I have to the program you are using. The way I tested was by having a coordinator with the CLI example sending attribute requests to the radiator. I saw some of the same behavior that you are seeing. When sending attribute read request for the time status attribute in the Time cluster, or the battery voltage attribute in the Power Configuration cluster, the radiator sent a successful read attributes response, and I got the attribute value. When I tried to read battery percentage remaining, I got unsupported attribute. I also used a sniffer to look at the network traffic to confirm this. You can see the two read attribute response packets below, one for battery voltage, and one for battery percentage remaining.

    From what I can see, the attribute is implemented correctly, so I cannot see any reason why attributes from the extended attribute list are not working, while attributes from the regular list are. I will ask internally to see if anyone knows why this might be.

    Rohit Rajapure said:
    addr - how to get coordinator address in endpoint

     If you have the short address of the coordinator, you can use the function zb_zdo_ieee_addr_req to send a IEEE_addr_req primitive to get the IEEE, or long, address of the coordinator, which is what you should use as addr. Since it is a coordinator, the short address should be 0x0000.

    Rohit Rajapure said:
    dst_addr_mode - in which file I get address mode

     The address modes are found here. You should use ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT or ZB_APS_ADDR_MODE_16_ENDP_PRESENT, depending on whether the destination endpoint is present or not.

    Rohit Rajapure said:
    dst-ep - is this coordinator end point ? if yes how to read this ?

     Yes, this is the endpoint of the node you are sending the command to, so in this case it will be the coordinator. If you have the coordinators short address, then you can get the endpoint by sending an active endpoint request using zb_zdo_active_ep_req.

    Rohit Rajapure said:
    ep- this means my endpoint device id - (example THERMOSTAT_EP)

     Correct. This is the endpoint of the source, the one sending the message, which in this case is the thermostat endpoint you have set in your code.

    Rohit Rajapure said:
    cb - it should be NULL or we can give function to read data?

     It can be NULL or a pointer to a callback function for getting command send status.

    The definition of ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ can be found in the file external/zboss/include/zcl/zb_zcl_commands.h.

    Best regards,

    Marte

  • Hi Marte,

    Thank you so much for the feedback.

    - Yes, even the same issue I am facing for thermostat ids. I have initialized local_temperature Id first but the same issue. When I tried to access using GUI it disappears like power percentage.

    - So, I again crossed checked your file (the one which you have shared in the previous post). But it looks the same. Still the same issue.

    - Power cluster and thermostat cluster not working as expected to be.

    And, thank you for sending the read request details. I will create functions and check if I get any reply from the coordinator.

    Hello Update,

    I tried to read the request,

    - Can you please check is correct,

    static void active_ep_callback(zb_uint8_t param)
    {
      zb_buf_t *buf = ZB_BUF_FROM_REF(param);
    
      zb_uint8_t *zdp_cmd = ZB_BUF_BEGIN(buf);
    
      zb_zdo_ep_resp_t *resp = (zb_zdo_ep_resp_t*)zdp_cmd;
    
    //  zb_uint8_t *ep_list = zdp_cmd + sizeof(zb_zdo_ep_resp_t);
    //
    //  if (resp->status != ZB_ZDP_STATUS_SUCCESS || resp->nwk_addr != 0x0)
    //  {
    //    TRACE_MSG(TRACE_APS1, "Error incorrect status/addr", (FMT__0));
    //    g_error++;
    //  }
    //  
    //  if (resp->ep_count != 1 || *ep_list != 1)
    //  {
    //    TRACE_MSG(TRACE_APS3, "Error incorrect ep count or ep value", (FMT__0));
    //    g_error++;
    //  }
     // send_match_desc_req(buf);
    }
    
    //static void send_active_ep_req(zb_buf_t *buf)
    //{
    //  zb_zdo_active_ep_req_t *req;
    //  ZB_BUF_INITIAL_ALLOC(buf, sizeof(zb_zdo_active_ep_req_t), req);
    //  req->nwk_addr = 0; //coord addr
    //  zb_zdo_active_ep_req(ZB_REF_FROM_BUF(buf), active_ep_callback);
    //}
    
    ////////////////////////////////////////////////////////////////////////////////
    ///
    /// \brief Requests the RTC from the coordinator
    ///
    /// \param RTC is sent in seconds format. Seconds from the year 2000
    ///
    /// \return void (no return value)
    ///
    /// \par example
    /// Call e.g. RTC_vRequestTimeFromCoordiantor() \n
    ///
    ////////////////////////////////////////////////////////////////////////////////
    void vRTC_vRequestTimeFromCoordiantor(void) 
    {
    
        zb_buf_t * p_buf;
    
        zb_uint8_t *cmd_ptr = NULL;
    
        ui16Addr = 0x0000;
    
        ui8Dst_addr = zb_zdo_active_ep_req(ZB_REF_FROM_BUF(p_buf), active_ep_callback);
    
    //    send_active_ep_req(p_buf);
    
        ZB_ZCL_GENERAL_INIT_READ_ATTR_REQ(p_buf, cmd_ptr, ZB_ZCL_ATTR_TIME_TIME_ID);
    
        ZB_ZCL_GENERAL_ADD_ID_READ_ATTR_REQ(cmd_ptr, ZB_ZCL_ATTR_TIME_TIME_ID);
    
        ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ(p_buf, 
                                          cmd_ptr, 
                                          ui16Addr, 
                                          ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                          ui8Dst_addr,
                                          THERMOSTAT_SENSOR_ENDPOINT, 
                                          ZB_AF_HA_PROFILE_ID,
                                          ZB_ZCL_CLUSTER_ID_TIME, 
                                          NULL);
    }

    - I didn't get the ieee_request so I kept 0x0000 there and from the address field, I wrote function as i understood but I didn't get any response.

    Can you please help me with what I did wrong?

    Or do i need to create client also for this time cluster or is it server only? Because. I am requesting this from End point device to Gateway (nRF to Gateway).

    Please guide me.

    Thanks and Regards

    Rohit R

  • Hi,

    Does the gateway have the time cluster implemented? Do you know whether the gateway receives the read attributes request or not? I know you said earlier that you do not have another DK, but having a sniffer such as the nRF Sniffer for 802.15.4 to sniff the network traffic can be very helpful when working with Zigbee. With it you can see the packets sent on the network (if the sniffer has the network key), so you can see if the read attributes request seems to be sent correctly, and whether the gateway receives it and tries to send a response back. It is hard to help with this issue without knowing where the packet fails.

    The command itself looks correct. Be aware that ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ only sends the read attributes request to the other device, but it does not parse it. This is done internally by the stack. If you want to parse it yourself (instead of the stack doing it internally), you should use ZB_ZCL_GENERAL_GET_NEXT_READ_ATTR_RES(data_buf, read_attr_resp), with the following parameters:

    • data_buf: ID zb_bufid_t of a buffer containing read attribute response data
    • read_attr_resp: out pointer to zb_zcl_read_attr_res_t, containing Read attribute status record

    An example of this in use is in the CLI example, you can see this in the file components/zigbee/cli/zigbee_cli_cmd_attr.c. First, the function readattr_send() sends the read attributes command, as you do above. The other device (your gateway in this example) receives the command, and responds with a read attributes response, as described in the ZCL specification. The original device that sent the read command shall then be notified of the result and the value of the attribute. In the CLI example, this is handled by the function cli_agent_ep_handler_attr(), which is a handler used to 'intercept' every frame coming to the endpoint. When it is a read attributes command response, it calls the function print_read_attr_response(), which then parses the read attributes response.

    The stack does handle required commands internally be default, so it should handle read attribute response commands as well. The reason this is done the way it is in the CLI example is because this example wants to do something else with the response than what the stack does. Therefore, it should handle the response in another way, so it overrides the default handler such that cli_agent_ep_handler_attr() is called instead. If you want more control over the response, you can implement a handler to override this as well. It should not be necessary, and I am not sure if it will fix the problem, as I do not know how the gateway responds to the read attributes command, or if it even gets it. If you want to do this, you should set an endpoint receive hook with ZB_AF_SET_ENDPOINT_HANDLER().

    If you want to use this, you should add it to your main function where you are registering the device context:

    /* Register thermostat device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&thermostat_ctx);
    
    /* Set the endpoint receive hook */
    ZB_AF_SET_ENDPOINT_HANDLER(THERMOSTAT_SENSOR_ENDPOINT, thermostat_ep_handler);

    Then you must implement the endpoint handler function (here I called it thermostat_ep_handler), which will be the same as what the function cli_agent_ep_handler_attr() is for the CLI example. As I said, I do not see why this should be necessary unless you want to override what happens when you receive a response to the read attributes command. The first thing you should do anyway is to try and figure out where the read attributes command fails.

    Best regards,

    Marte

  • Hi Marte,

    Does the gateway have the time cluster implemented? Do you know whether the gateway receives the read attributes request or not? I

    - yes, I am sure because with this gateway they have developed using NXP. Which I am porting as I said previously. So, what they do is when RTC is invalid they are requesting from Gateway. Here is a snippet of nxp code.

    PUBLIC void vRTC_vRequestTimeFromCoordiantor(void) {
    	void * thisNet = ZPS_pvAplZdoGetNwkHandle();
    	ZPS_tsNwkNib * thisNib = ZPS_psNwkNibGetHandle(thisNet);
    
    	uint8 u8Seq;
    	tsZCL_Address sAddress;
    
    	uint16 au16AttributeRequestList[] = {E_CLD_TIME_ATTR_ID_TIME };
    	//sAddress.eAddressMode = E_ZCL_AM_BROADCAST;
    
    	sAddress.eAddressMode = E_ZCL_AM_BOUND;
    	sAddress.uAddress.u16DestinationAddress = thisNib->sTbl.psNtDisc[0].u16NwkAddr;
    
    	DBG_vPrintf(TRACE_RTC, "\nAPP State Event:  dst Address %04x \n",thisNib->sTbl.psNtDisc[0].u16NwkAddr);
    	DBG_vPrintf(TRACE_RTC, "\nAPP State Event:  dst Endpoint %02x \n",sDeviceState.sMatchDev[sDeviceState.u8Index].u8Ep);
    
    			eZCL_SendReadAttributesRequest(
    			0x01   /*u8MyEndpoint*/, //uint8            u8SourceEndPointId,
    			u8DestinationEndpointID,//sDeviceState.sMatchDev[sDeviceState.u8Index].u8Ep,//0x0A,  					 //uint8            u8DestinationEndPointId,
    			GENERAL_CLUSTER_ID_TIME,                  //Time uint16      u16ClusterId,
    			FALSE,               	 //bool_t           bDirectionIsServerToClient,
    			&sAddress,               //tsZCL_Address    *psDestinationAddress,
    			&u8Seq,            		 //uint8            *pu8TransactionSequenceNumber,
    			1, 						 //uint8             Anzahl der reuqests die durchgeführt werden,
    			FALSE,                   //bool_t            bIsManufacturerSpecific,
    			ZCL_MANUFACTURER_CODE,                  //uint16            u16ManufacturerCode,
    			au16AttributeRequestList //uint16            *pu16AttributeRequestList
    			);
    
    }

    I know you said earlier that you do not have another DK, but having a sniffer such as the nRF Sniffer for 802.15.4 to sniff the network traffic

    - Ya, I know, to be honest, we are working from home due to this covid and I don't have other Dv-kit or dongle. But in few days I will arrange the dongle.

    Be aware that ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ only sends the read attributes request to the other device, but it does not parse it. This is done internally by the stack. If you want to parse it yourself (instead of the stack doing it internally), you should use ZB_ZCL_GENERAL_GET_NEXT_READ_ATTR_RES(data_buf, read_attr_resp), with the following parameters:

    - Okay, as per my understanding I did like this, attached snippet.

    - So, as said in the first point this function I request when RTC is valid.

    void vRTC_vRequestTimeFromCoordiantor(void) 
    {
    
        zb_buf_t * p_buf;
    
        zb_uint8_t *cmd_ptr = NULL;
    
        ui16Addr = 0x0000;
    
        ui8Dst_addr = zb_zdo_active_ep_req(ZB_REF_FROM_BUF(p_buf), active_ep_callback);
    
        ZB_ZCL_GENERAL_INIT_READ_ATTR_REQ(p_buf, cmd_ptr, ZB_ZCL_ATTR_TIME_TIME_ID);
    
        ZB_ZCL_GENERAL_ADD_ID_READ_ATTR_REQ(cmd_ptr, ZB_ZCL_ATTR_TIME_TIME_ID);
    
        ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ(p_buf, 
                                          cmd_ptr, 
                                          ui16Addr, 
                                          ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                          ui8Dst_addr,
                                          THERMOSTAT_SENSOR_ENDPOINT, 
                                          ZB_AF_HA_PROFILE_ID,
                                          ZB_ZCL_CLUSTER_ID_TIME, 
                                          NULL);
    
        zb_buf_t *buf;
        zb_zcl_read_attr_res_t *read_attr_resp;
    
        ZB_ZCL_GENERAL_GET_NEXT_READ_ATTR_RES(buf, read_attr_resp);
    
    }

    In the CLI example, this is handled by the function cli_agent_ep_handler_attr(),

    - yes, I saw this code But what are these points. Is it required?. I got confused so I did not include it in my code.

    static zb_uint8_t cli_agent_ep_handler_attr(zb_uint8_t param)
    {
        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);
        zb_int8_t row;
    
        /* Get the row in the requests table according by the sequence number */
        row = get_attr_table_row_by_sn(p_cmd_info->seq_number);
        if (row == -1)
        {
            return ZB_FALSE;
        }
    
        attr_query_t * p_row = &(m_attr_table[row]);
        if (!is_response(p_cmd_info, p_row))
        {
            return ZB_FALSE;
        }
    
        if (p_cmd_info->cmd_id == ZB_ZCL_CMD_DEFAULT_RESP)
        {
            zb_zcl_default_resp_payload_t * p_def_resp;
            p_def_resp = ZB_ZCL_READ_DEFAULT_RESP(p_zcl_cmd_buf);
            nrf_cli_fprintf(p_row->p_cli, NRF_CLI_ERROR, "Error: Default Response received; ");
            nrf_cli_fprintf(p_row->p_cli, NRF_CLI_ERROR, "Command: %d, Status: %d ",
                            p_def_resp->command_id, p_def_resp->status);
        }
        else
        {
            if (p_row->req_type == ATTR_READ_REQUEST)
            {
                print_read_attr_response(p_zcl_cmd_buf, p_row);
            }
            else
            {
                print_write_attr_response(p_zcl_cmd_buf, p_row);
            }
        }
        /* Cancel the ongoing alarm which was to erase the row... */
        UNUSED_RETURN_VALUE(ZB_SCHEDULE_ALARM_CANCEL(invalidate_row_cb, row));
        /* ...and erase it manually */
        invalidate_row(row);
    
        ZB_FREE_BUF(p_zcl_cmd_buf);
        return ZB_TRUE;
    }

    1)  row = get_attr_table_row_by_sn(p_cmd_info->seq_number) ?

    2) attr_query_t * p_row = &(m_attr_table[row]);?

    3) If and else statments from above snippet?

    - Or can copy this functions in my code for handler creation as you said?

    And, one more this is observed that if I run the code, (previously attached snippet)

    These 2 lines of code not affecting from active_ep_callback()

    1) zb_zdo_ep_resp_t *resp = (zb_zdo_ep_resp_t*)zdp_cmd;

    2) zb_uint8_t *ep_list = zdp_cmd + sizeof(zb_zdo_ep_resp_t);

    These are my test observation. Let me know your feedback on this same.

    Thanks and Regards

    Rohit R

Related