Zigbee Shell Get list of attributes in cluster

We can get the active end points and list of cluster in end points.

But is there a way to get list of attribute and types of attribute in each cluster?

Parents
  • Hi,

    You can use the discover attributes command to get the attributes and types by calling ZB_ZCL_GENERAL_DISC_ATTR_REQ_A().

    This command is not part of the Zigbee shell library, so if you want to use it as a shell command, you must implement it as a custom shell command.
    Here is an example code showing how to do this:

    #include <zephyr/shell/shell.h>
    #include <zboss_api.h>
    #include <zigbee/zigbee_error_handler.h>
    #include <zigbee/zigbee_app_utils.h>
    #include <zb_nrf_platform.h>
    
    #include <zigbee/zigbee_shell.h>
    #include "zigbee_shell_utils.h"
    
    static int cmd_zb_discover_attributes(const struct shell *shell, size_t argc,
    			       char **argv)
    {
        zb_zcl_disc_attr_req_t *req;
        zb_bufid_t bufid;
        struct zcl_packet_info *packet_info;
        zb_uint8_t *cmd_ptr;
        bufid = zb_buf_get_out();
    
        struct ctx_entry *entry = ctx_mgr_new_entry(CTX_MGR_ATTR_REQ_ENTRY_TYPE);
    
        if (bufid == ZB_BUF_INVALID)
        {
            shell_print(shell, "No Zigbee buffer available");
        }
    
        req = zb_buf_initial_alloc(bufid, sizeof(*req));
    
        packet_info = &(entry->zcl_data.pkt_info);
        packet_info->dst_addr_mode = parse_address(*(++argv), &(packet_info->dst_addr), ADDR_ANY);
    
        if (packet_info->dst_addr_mode == ADDR_INVALID) {
    		shell_print(shell, "Invalid address");
    		goto readattr_error;
    	}
    
    	if (!zb_shell_sscan_uint8(*(++argv), &(packet_info->dst_ep))) {
    		shell_print(shell, "Incorrect remote endpoint");
    		goto readattr_error;
    	}
    
    	if (!parse_hex_u16(*(++argv), &(packet_info->cluster_id))) {
    		shell_print(shell, "Invalid cluster id");
    		goto readattr_error;
    	}
    
        if (!parse_hex_u16(*(++argv), &(packet_info->prof_id))) {
    		shell_print(shell, "Invalid profile id");
    		goto readattr_error;
    	}
    
        if (!parse_hex_u16(*(++argv), &(req->start_attr_id))) {
    		shell_print(shell, "Invalid attribute id");
    		goto readattr_error;
    	}
    
        req->maximum=1;
    
        packet_info->buffer = bufid;
        packet_info->ep = zb_shell_get_endpoint();
    
        ZB_ZCL_GENERAL_DISC_ATTR_REQ_A(bufid,
                                       cmd_ptr,
                                       ZB_ZCL_FRAME_DIRECTION_TO_SRV,
                                       ZB_ZCL_ENABLE_DEFAULT_RESPONSE,
                                       req->start_attr_id,
                                       req->maximum,
                                       packet_info->dst_addr,
                                       packet_info->dst_addr_mode,
                                       packet_info->dst_ep,
                                       packet_info->ep,
                                       packet_info->prof_id,
                                       packet_info->cluster_id,
                                       0);
    
        return 0;
    
        readattr_error:
    	/* Mark data structure as free. */
    	ctx_mgr_delete_entry(entry);
    	return -EINVAL;
    }
    
    
    SHELL_STATIC_SUBCMD_SET_CREATE(sub_zb,
        SHELL_CMD_ARG(attr_discover, NULL, "Discover ZCL attributes", cmd_zb_discover_attributes, 6, 1),
    	SHELL_SUBCMD_SET_END /* Array terminated. */
    );
    
    SHELL_CMD_REGISTER(zb, &sub_zb, "Custom Zigbee commands", NULL);

    This creates a custom shell command with the following format:

    zb attr_discover h:dst_addr d:ep h:cluster [-c] h:profile h:attr_id h:start_attribute 

    Please note that this code is not thoroughly tested or qualified and should be considered provided “as-is”. Please test it with your application and let me know if you find any issues.

    Best regards,
    Marte

  • Hi Marte 
    we are getting values but not sure if its correct as it doesn't much make sense.
    Can you please how can we decode response in meaningfull manner?


    void send_zb_discover_attributes(zb_uint16_t short_addr, uint16_t ep, zb_uint16_t cluster_id)
    {
     zb_bufid_t buf = zb_buf_get_out();
     zb_zcl_disc_attr_req_t *req_param = zb_buf_initial_alloc(buf, sizeof(zb_zcl_disc_attr_req_t));
     zb_uint8_t *cmd_ptr;
     
     req_param->maximum = 10;
     req_param->start_attr_id = 0;
     ZB_ZCL_GENERAL_DISC_ATTR_REQ_A(buf,
               cmd_ptr,
               ZB_ZCL_FRAME_DIRECTION_TO_SRV,
               ZB_ZCL_ENABLE_DEFAULT_RESPONSE,
               req_param->start_attr_id,
               req_param->maximum,
               short_addr,
               ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
               ep,
               ZIGBEE_COORDINATOR_ENDPOINT,
               ZB_AF_HA_PROFILE_ID,
               cluster_id,
               handle_discover_attributes_response);
    }
    
    zb_zcl_disc_attr_info_t* get_next_disc_attr_res(zb_bufid_t data_buf)
    {
        zb_zcl_disc_attr_info_t *disc_attr_info;
                                                                                            \
      (disc_attr_info) = zb_buf_len(data_buf) >= ZB_ZCL_DISC_ATTR_RESP_SIZE ?               \
        (zb_zcl_disc_attr_info_t*)zb_buf_begin(data_buf) : (zb_zcl_disc_attr_info_t*)0;     \
                                                                                            \
      if (disc_attr_info)                                                                   \
      {                                                                                     \
        ZB_ZCL_HTOLE16_INPLACE(&(disc_attr_info)->attr_id);                                 \
                                                                                            \
        (void)zb_buf_cut_left((data_buf), ZB_ZCL_DISC_ATTR_RESP_SIZE);                      \
      }                                                                                     \
        
        return disc_attr_info;
    }
    
    void handle_discover_attributes_response(zb_bufid_t buf)
    {
     zb_zcl_disc_attr_res_t *disc_attr_res;
     zb_zcl_disc_attr_info_t *disc_attr_info;
     zb_bool_t complete;
    
     // Get the 'complete' field from the response
     ZB_ZCL_GENERAL_GET_COMPLETE_DISC_RES(buf, complete);
      while ((disc_attr_info = get_next_disc_attr_res(buf)) != NULL)
       {
        // Process each discovered attribute
        printf("Discovered attribute: ID 0x%04x, Type 0x%02x\n", 
         disc_attr_info->attr_id, disc_attr_info->data_type);
    
       }
    
     printf("Discovery complete: %s\n", complete ? "Yes" : "No");
    }

Reply
  • Hi Marte 
    we are getting values but not sure if its correct as it doesn't much make sense.
    Can you please how can we decode response in meaningfull manner?


    void send_zb_discover_attributes(zb_uint16_t short_addr, uint16_t ep, zb_uint16_t cluster_id)
    {
     zb_bufid_t buf = zb_buf_get_out();
     zb_zcl_disc_attr_req_t *req_param = zb_buf_initial_alloc(buf, sizeof(zb_zcl_disc_attr_req_t));
     zb_uint8_t *cmd_ptr;
     
     req_param->maximum = 10;
     req_param->start_attr_id = 0;
     ZB_ZCL_GENERAL_DISC_ATTR_REQ_A(buf,
               cmd_ptr,
               ZB_ZCL_FRAME_DIRECTION_TO_SRV,
               ZB_ZCL_ENABLE_DEFAULT_RESPONSE,
               req_param->start_attr_id,
               req_param->maximum,
               short_addr,
               ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
               ep,
               ZIGBEE_COORDINATOR_ENDPOINT,
               ZB_AF_HA_PROFILE_ID,
               cluster_id,
               handle_discover_attributes_response);
    }
    
    zb_zcl_disc_attr_info_t* get_next_disc_attr_res(zb_bufid_t data_buf)
    {
        zb_zcl_disc_attr_info_t *disc_attr_info;
                                                                                            \
      (disc_attr_info) = zb_buf_len(data_buf) >= ZB_ZCL_DISC_ATTR_RESP_SIZE ?               \
        (zb_zcl_disc_attr_info_t*)zb_buf_begin(data_buf) : (zb_zcl_disc_attr_info_t*)0;     \
                                                                                            \
      if (disc_attr_info)                                                                   \
      {                                                                                     \
        ZB_ZCL_HTOLE16_INPLACE(&(disc_attr_info)->attr_id);                                 \
                                                                                            \
        (void)zb_buf_cut_left((data_buf), ZB_ZCL_DISC_ATTR_RESP_SIZE);                      \
      }                                                                                     \
        
        return disc_attr_info;
    }
    
    void handle_discover_attributes_response(zb_bufid_t buf)
    {
     zb_zcl_disc_attr_res_t *disc_attr_res;
     zb_zcl_disc_attr_info_t *disc_attr_info;
     zb_bool_t complete;
    
     // Get the 'complete' field from the response
     ZB_ZCL_GENERAL_GET_COMPLETE_DISC_RES(buf, complete);
      while ((disc_attr_info = get_next_disc_attr_res(buf)) != NULL)
       {
        // Process each discovered attribute
        printf("Discovered attribute: ID 0x%04x, Type 0x%02x\n", 
         disc_attr_info->attr_id, disc_attr_info->data_type);
    
       }
    
     printf("Discovery complete: %s\n", complete ? "Yes" : "No");
    }

Children
Related