Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strange behavior in reports (TZ-120) #27

Closed
diazmanuel opened this issue May 19, 2023 · 7 comments
Closed

strange behavior in reports (TZ-120) #27

diazmanuel opened this issue May 19, 2023 · 7 comments

Comments

@diazmanuel
Copy link

I am currently working on the following system. A gateway that acts as a zigbee network coordinator, a device (switch) that handles multiple outputs, and a sensor device for each of these outputs. The coordinator is in charge of performing the binding between the different endpoints of the switch and the sensors. and the switch establishes a binding between itself and the gateway to report a custom cluster each time an output is activated from the sensor

When analyzing the system, I found an error in the behavior of the switch reports to the gateway. After binding the switch to the gateway, the reports are configured as follows

static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx)
{

if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
    ESP_LOGI(TAG, "bind_cb status:%d", zdo_status);
    /* configure report attribute command */
    esp_zb_zcl_config_report_cmd_t report_cmd;
    report_cmd.zcl_basic_cmd.dst_addr_u.addr_short=esp_zb_get_short_address();
    report_cmd.zcl_basic_cmd.dst_endpoint = 1;
    report_cmd.zcl_basic_cmd.src_endpoint = 1;
    report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
    report_cmd.clusterID = 0xFFFE;
    report_cmd.attributeID = 0;
    report_cmd.attrType = ESP_ZB_ZCL_ATTR_TYPE_U32;
    report_cmd.min_interval = 0;
    report_cmd.max_interval = 30;
    report_cmd.reportable_change =3;
    esp_zb_zcl_config_report_cmd_req(&report_cmd);
}

}

and the callback of the sensor device report is handle as follow:

static void esp_zb_dev_reporting_cb(esp_zb_zcl_addr_t *addr, uint8_t endpoint, uint16_t cluster_id, uint16_t attr_id, esp_zb_zcl_attr_type_t attr_type, void *value)
{

esp_zb_zcl_attr_t *value_r = esp_zb_zcl_get_attribute(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0);
*((uint32_t*) value_r->data_p)+=1;
esp_zb_zcl_set_attribute_val(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0,value_r->data_p);

}

then the expected behavior of the system would be that the switch reports to the gateway every 30 seconds and when the switch receives a report from the sensor it increases the value of attribute 0 of the custom cluster 0XFFFE by 1, if the value increases exceeds what is established in the reports configuration (in this case 3) a new report should be produced from the switch to the gateway.

The real behavior was the following, in principle the switch reported every 30 seconds to the gateway as expected, but upon receiving the command from a sensor the callback of said report was triggered and increased the custom attribute, in theory the switch should not report to the gateway since the increase of said attribute was less than 3 compared to its original value but contrary to what was expected, the switch generated a report to the gateway ignoring the configuration condition (also verify that this report did not correspond to the periodic report every 30 seconds). In addition to having generated the report, it would seem that he deleted the configuration because from that moment on, periodic reports were no longer generated, nor were reports generated when modifying that attribute of the customized cluster again.

after that i try to force the reports after writing the attribute ,by modifying the callback of the incoming reports from the sensors as follows.

static void esp_zb_dev_reporting_cb(esp_zb_zcl_addr_t *addr, uint8_t endpoint, uint16_t cluster_id, uint16_t attr_id, esp_zb_zcl_attr_type_t attr_type, void *value)

{

esp_zb_zcl_report_attr_cmd_t des;
des.zcl_basic_cmd.dst_addr_u.addr_short=0;   // gateway
des.zcl_basic_cmd.dst_endpoint = 1;
des.zcl_basic_cmd.src_endpoint = 1;
des.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
des.clusterID = 0xFFFE;
des.attributeID = 0;
des.cluster_role=ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
esp_zb_zcl_attr_t *value_r = esp_zb_zcl_get_attribute(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0);
*((uint32_t*) value_r->data_p)+=1;
esp_zb_zcl_set_attribute_val(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0,value_r->data_p);
esp_zb_zcl_report_attr_cmd_req(&des);

}
The behavior was similar to the previous one, only this time every time a sensor report arrived, the switch modified the attribute and when forcing the report it was sent, but as in the previous case, the established configuration of the periodic report was ignored and the minimum value that said report will generate

I think writing the custom cluster attribute ignores and clears the report settings. I would like to know if this can be due to a bad behavior of the sdk or if I am doing the configuration wrong

thanks

@likunqiao097304
Copy link
Contributor

likunqiao097304 commented May 22, 2023

Since you didn't get the period 30 seconds report and also didn't apply the rule of reportable change. It might be you didn't configure the report or bind correctly.
report_cmd.zcl_basic_cmd.dst_addr_u.addr_short=esp_zb_get_short_address(); this address should be switch

@diazmanuel
Copy link
Author

Maybe I am not explaining myself correctly, the code I show is the switch code, therefore esp_zb_get_short_address() obtains the switch address. It is also configured correctly because in principle periodic reports are sent, when modifying the attribute with the esp_zb_zcl_set_attribute_val function the report stops working

@tom-borcin tom-borcin changed the title strange behavior in reports strange behavior in reports May 23, 2023
@github-actions github-actions bot changed the title strange behavior in reports strange behavior in reports (TZ-120) May 23, 2023
@likunqiao097304
Copy link
Contributor

@diazmanuel Sorry for the late following up. If I understand correctly, you would like to set the configure report to switch and ask switch to send the report to gateway in period of 30 seconds or attribute change larger than 3. However, you got a report command which is less than 3 delta value nor in 30 seconds period first time, and later all future expected report command is stopped. Right?

Firstly, for the work around solution, you could use esp_zb_zcl_report_attr_cmd_req to directly call this function send report to gateway, with a timer alarm 30 seconds (esp_zb_scheduler_alarm) or based on the attribute change more than 3 to trigger.

Secondly, could you show me your code how do you register the custom attribute on switch side and how do you do the binding from switch to gateway, I'd like to see if there is any other issue. It might be some issue when we set esp_zb_zcl_set_attribute_val on customized attribute, I will try to duplicate your condition to fix it.

@diazmanuel
Copy link
Author

diazmanuel commented May 29, 2023

If I understand correctly, you would like to set the configure report to switch and ask switch to send the report to gateway in period of 30 seconds or attribute change larger than 3.
yes thats right but its stop working when i set that attribut. when the attribute is incremented by 1 the reports stop working. i will add the code so its more simple to understand.

here is the code of the switch


#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_HA_customized_switch.h"
#include "nvs_flash.h"

#if !defined ZB_ED_ROLE
#error Define ZB_ED_ROLE in idf.py menuconfig to compile light switch (End Device) source code.
#endif

static const char *TAG = "ESP_HA_ON_OFF_SWITCH";

struct cluster_data_t cluster_data;


typedef struct zdo_info_ctx_s {
    uint8_t endpoint;
    esp_zb_ieee_addr_t long_addr;
} zdo_info_user_ctx_t;



static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
{
    ESP_ERROR_CHECK(esp_zb_bdb_start_top_level_commissioning(mode_mask));
}

static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx)
{
    if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
        ESP_LOGI(TAG, "bind_cb status:%d", zdo_status);
        /* configure report attribute command */
        esp_zb_zcl_config_report_cmd_t report_cmd;
        report_cmd.zcl_basic_cmd.dst_addr_u.addr_short=esp_zb_get_short_address();
        report_cmd.zcl_basic_cmd.dst_endpoint = 1;
        report_cmd.zcl_basic_cmd.src_endpoint = 1;
        report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
        report_cmd.clusterID = 0xFFFE;
        report_cmd.attributeID = 0;
        report_cmd.attrType = ESP_ZB_ZCL_ATTR_TYPE_U32;
        report_cmd.min_interval = 1;
        report_cmd.max_interval = 30;
        report_cmd.reportable_change = 1;
        esp_zb_zcl_config_report_cmd_req(&report_cmd);
    }
}
static void esp_zb_dev_reporting_cb(esp_zb_zcl_addr_t *addr, uint8_t endpoint, uint16_t cluster_id,
                                    uint16_t attr_id, esp_zb_zcl_attr_type_t attr_type, void *value)
{
    esp_zb_zcl_report_attr_cmd_t des;
    des.zcl_basic_cmd.dst_addr_u.addr_short=0;
    des.zcl_basic_cmd.dst_endpoint = 1;
    des.zcl_basic_cmd.src_endpoint = 1;
    des.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
    des.clusterID = 0xFFFE;
    des.attributeID = 0;
    des.cluster_role=ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;


    ESP_LOGI(TAG, "Switch got report attribute from address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, ID: %ld,cluster_id:0x%x,attr_id:0x%x,value:%d,attr_type:0x%x, endpoint:%d", addr->u.ieee_addr[7], addr->u.ieee_addr[6], addr->u.ieee_addr[5], addr->u.ieee_addr[4], addr->u.ieee_addr[3], addr->u.ieee_addr[2], addr->u.ieee_addr[1], addr->u.ieee_addr[0], addr->u.src_id , cluster_id, attr_id, *(uint8_t *)value, attr_type,endpoint);
    esp_zb_zcl_attr_t *value_r = esp_zb_zcl_get_attribute(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0);
    *((uint32_t*) value_r->data_p)+=1;
    //when the incomming report from a end device arrives here i increment the attribut that reports to the gateway.
    //when calling the funtion esp_zb_zcl_set_attribute_val below a report is generate (ignoring the configuration of reportable_change)
    //but the periodic report stop working. also if they enter this cb again and call the funtion esp_zb_zcl_set_attribute_val this time the report dont generate.
    
    //So the periodic report only works if i never call the funtion esp_zb_zcl_set_attribute_val ,
    //and when i call this funtion they generate 1 report and the reports stop working, the only wait to force the report is calling the funtion esp_zb_zcl_report_attr_cmd_req.
    esp_zb_zcl_set_attribute_val(1,0xFFFE,ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,0,value_r->data_p);   
    //esp_zb_zcl_report_attr_cmd_req(&des);
    ESP_LOGI(TAG,"value %lu ",aux);
}
static void ieee_cb(esp_zb_zdp_status_t zdo_status, esp_zb_ieee_addr_t ieee_addr, void *user_ctx)
{
    
    if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {

        esp_zb_zdo_bind_req_param_t bind_req;
        esp_zb_get_long_address(bind_req.src_address);
        bind_req.src_endp = 1;
        bind_req.cluster_id = 0xFFFE;
        bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
        memcpy(bind_req.dst_address_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));

        ESP_LOGI(TAG, "local address is:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
                bind_req.src_address[7], bind_req.src_address[6], bind_req.src_address[5],
               bind_req.src_address[4], bind_req.src_address[3], bind_req.src_address[2],
                bind_req.src_address[1], bind_req.src_address[0]);

        bind_req.dst_endp = 1;
        bind_req.req_dst_addr = esp_zb_get_short_address();
        static zdo_info_user_ctx_t test_info_ctx;
        test_info_ctx.endpoint = 1;
        memcpy(test_info_ctx.long_addr, ieee_addr, sizeof(esp_zb_ieee_addr_t));
        esp_zb_zdo_device_bind_req(&bind_req, bind_cb, (void *) & (test_info_ctx));
    }
}



static void esp_zb_read_resp_cb(esp_zb_zcl_status_t status, uint16_t cluster_id, uint16_t attr_id, esp_zb_zcl_attr_type_t attr_type, void *value)
{
    ESP_LOGI(TAG, "Switch got read attribute response with status:%d,cluster_id:0x%x,attr_id:0x%x,value:%d,attr_type:0x%x", status, cluster_id, attr_id, *(uint8_t *)value, attr_type);
}

void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
{
    
    uint32_t *p_sg_p       = signal_struct->p_app_signal;
    esp_err_t err_status = signal_struct->esp_err_status;
    esp_zb_app_signal_type_t sig_type = *p_sg_p;
    switch (sig_type) {
    case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
        ESP_LOGI(TAG, "Zigbee stack initialized");
        esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
        break;
    case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
    case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:
        if (err_status == ESP_OK) {
            ESP_LOGI(TAG, "Start network steering");
            esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        } else {
            /* commissioning failed */
            ESP_LOGW(TAG, "Failed to initialize Zigbee stack (status: %d)", err_status);
            esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
        }
        
        break; 
    case ESP_ZB_BDB_SIGNAL_STEERING:
        if (err_status == ESP_OK) {
            esp_zb_ieee_addr_t extended_pan_id;
            esp_zb_get_extended_pan_id(extended_pan_id);
            ESP_LOGI(TAG, "Joined network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d)",
                     extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4],
                     extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0],
                     esp_zb_get_pan_id(), esp_zb_get_current_channel());
                     
            esp_zb_zdo_ieee_addr_req_param_t ieee_req;
            ieee_req.addr_of_interest = 0;
            ieee_req.dst_nwk_addr = 0;
            ieee_req.request_type = 0;
            ieee_req.start_index = 0;
            esp_zb_zdo_ieee_addr_req(&ieee_req, ieee_cb, NULL);
        } else {
            ESP_LOGI(TAG, "Network steering was not successful (status: %d)", err_status);
            esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_STEERING, 1000);
        }
        break;
    case ESP_ZB_ZDO_SIGNAL_LEAVE:
        esp_zb_zdo_signal_leave_params_t *leave_params = (esp_zb_zdo_signal_leave_params_t *)esp_zb_app_signal_get_params(p_sg_p);
        if (leave_params->leave_type == ESP_ZB_NWK_LEAVE_TYPE_RESET) {
            ESP_LOGI(TAG, "Reset device");
        }
        break;
    default:
        ESP_LOGI(TAG, "ZDO signal: %d, status: %d", sig_type, err_status);
        break;
    }
}
void attr_cbxxx(uint8_t status, uint8_t endpoint, uint16_t cluster_id, uint16_t attr_id, void *value)
{
    ESP_LOGI(TAG,"Callback aaaa");
}
void attr_cb(uint8_t status, esp_zb_zcl_attr_type_t data_type, void *value)
{
    ESP_LOGI(TAG,"Callback value");
}
static void esp_zb_task(void *pvParameters)
{
    /* initialize Zigbee stack with Zigbee end-device config */
    esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
    esp_zb_init(&zb_nwk_cfg);

    esp_zb_ep_list_t *esp_zb_ep_list = esp_zb_ep_list_create();

    esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
    esp_zb_attribute_list_t *FFFE = esp_zb_zcl_attr_list_create(0xFFFE);
    esp_zb_custom_cluster_add_custom_attr(FFFE, 0x00, ESP_ZB_ZCL_ATTR_TYPE_U32, ESP_ZB_ZCL_ATTR_ACCESS_READ_WRITE | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,&cluster_data.FFFE_flag);
    esp_zb_custom_cluster_add_custom_attr(FFFE, 0x01, ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_WRITE | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,&cluster_data.FFFE_away);
    esp_zb_custom_cluster_add_custom_attr(FFFE, 0x02, ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,&cluster_data.FFFE_hum);
    esp_zb_custom_cluster_add_custom_attr(FFFE, 0x03, ESP_ZB_ZCL_ATTR_TYPE_S16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,&cluster_data.FFFE_bat);
    esp_zb_custom_cluster_add_custom_attr(FFFE, 0x04, ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING, ESP_ZB_ZCL_ATTR_ACCESS_WRITE_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,cluster_data.FFFE_crono);

    esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list, FFFE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list, 1, 260, ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID);

    esp_zb_on_off_cluster_cfg_t on_off_cfg;
    on_off_cfg.on_off = ESP_ZB_ZCL_ON_OFF_ON_OFF_DEFAULT_VALUE;
    esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create(&on_off_cfg);
    esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_on_off_cluster(esp_zb_cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
    
    esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list, 9, 260, ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID);

    esp_zb_attribute_list_t *FFFC;
    for(int i=0;i<ZONAS;i++){
        esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
        FFFC = esp_zb_zcl_attr_list_create(0xFFFC);
        esp_zb_custom_cluster_add_custom_attr(FFFC, 0x00, ESP_ZB_ZCL_ATTR_TYPE_U32, ESP_ZB_ZCL_ATTR_ACCESS_READ_WRITE | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING,&(cluster_data.FFFC_valve[i]));
        esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list, FFFC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
        esp_zb_ep_list_add_ep(esp_zb_ep_list, esp_zb_cluster_list, 2+i, 260, ESP_ZB_HA_CUSTOM_ATTR_DEVICE_ID);
    }


    esp_zb_device_register(esp_zb_ep_list);

    esp_zb_device_add_report_attr_cb(esp_zb_dev_reporting_cb);
    esp_zb_add_read_attr_resp_cb(1, esp_zb_read_resp_cb);
    esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK);


    ESP_ERROR_CHECK(esp_zb_start(false));
    esp_zb_main_loop_iteration();
}

void app_main(void)
{
    esp_zb_platform_config_t config = {
        .radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(),
        .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(),
    };
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_zb_platform_config(&config));

    xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
}

In addition, the gateway makes a bind between the end device and the switch. when the end device reports to the switch, it increases the attribute and generates a report to the gateway

@likunqiao097304
Copy link
Contributor

@diazmanuel Hi, I have tried to duplicate most of your code on my side. And here are some results.

  1. I used level control cluster's attribute to do binding and config report. It worked fine. It can send the report to remote device in period of max interval seconds or do esp_zb_zcl_set_attribute_val attribute change larger than delta_change value.

  2. I also tried to use the same customized cluster (0xfffe) with attribute (0x0) you created to do binding and config report. It could periodically send the report message (let's say 30 seconds). I also couldn't receive a report if attribute value is larger than the delta_change by using esp_zb_zcl_set_attribute_val. However, even I couldn't send the report by using esp_zb_zcl_set_attribute_val, I still can get the period report, it didn't stop. Yes, there is a bug, but strange behavior is different than yours.

  3. The bug is that our structure defines esp_zb_zcl_config_report_cmd_t reportable_change as uint16_t. It should varies depends on the attrType. The fixes will be release either today or next week.

Again, for different behavior that you saw device stop reporting after esp_zb_zcl_set_attribute_val. It might be binding issue not report configuration.

@likunqiao097304
Copy link
Contributor

@diazmanuel The latest release has been fixed the reportable_change type from uint16_t to void type. Please try it out.

@diazmanuel
Copy link
Author

@likunqiao097304 with this change the strange behavior that it had disappeared, now it works correctly thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants