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?
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?
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_discoverh: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");
}Hi,
If you want to intercept the Discover Attributes Response you need to register an endpoint handler with ZB_AF_SET_ENDPOINT_HANDLER to intercept the ZCL packets. See more about this in Configuring default ZCL command handler override. Inside the signal handler you can check the cluster ID and command ID and handle the ZCL packet based on this.
Best regards,
Marte