espressif / esp-zigbee-sdk

Espressif Zigbee SDK
Apache License 2.0
153 stars 26 forks source link

Unable to report multistate value (TZ-963) #372

Open Arthuret opened 2 months ago

Arthuret commented 2 months ago

Question

I want to create a multi-purpose switch (smart switch), that is able to register single, long, double, ... presses.

I read that many switches that offer this feature "abuse" the multistate input cluster, but I find it unavailable in the sdk (only the multistate value exists. The ID constants exists for the input, output and value, but only the value has a "add cluster" method).

The basic principle is to report a present value like an event, with the value the type (single, double, ...) of press.

I thought that the same process would be feasible with the multistate value, but no matter how I try to report the value, I always end up on an "UNREPORTABLE_ATTRIBUTE" error of some kind:

So how can I do my action reporting to Z2M ? Thanks

Additional context.

esp-zigbee-lib & esp-zboss-lib v 1.3.2 esp-idf updated on latest 5.2 branch

xieqinan commented 2 months ago

@Arthuret ,

I always end up on an "UNREPORTABLE_ATTRIBUTE" error of some kind:

It indicates that the attribute is not defined as reportable in the Zigbee Cluster Library specification.

It would be helpful if you could provide the error logs so we can better understand and diagnose the issue.

Arthuret commented 2 months ago

@xieqinan , Code of cluster initialisation :

static void esp_zb_task(void *pvParameters)
{
    /* initialize Zigbee stack */
    esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG();
    esp_zb_init(&zb_nwk_cfg);

    // ------------------------------ Cluster BASIC ------------------------------
    esp_zb_basic_cluster_cfg_t basic_cluster_cfg = {
        .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE,
        .power_source = 0x04, // DC Source
    };
    uint32_t ApplicationVersion = 0x01;
    uint32_t StackVersion = 0x02;
    uint32_t HWVersion = 0x01;
    DEFINE_PSTRING(ManufacturerName, "ArthuretTest");
    DEFINE_PSTRING(ModelIdentifier, "ESP32C6-1");
    DEFINE_PSTRING(DateCode, "20240619");

    esp_zb_attribute_list_t *basic_cluster = esp_zb_basic_cluster_create(&basic_cluster_cfg);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_APPLICATION_VERSION_ID, &ApplicationVersion);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_STACK_VERSION_ID, &StackVersion);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_HW_VERSION_ID, &HWVersion);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)&ManufacturerName);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)&ModelIdentifier);
    esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_DATE_CODE_ID, (void *)&DateCode);

    // ------------------------------ Cluster IDENTIFY ------------------------------
    esp_zb_identify_cluster_cfg_t identify_cluster_cfg = {
        .identify_time = 0,
    };
    esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_identify_cluster_create(&identify_cluster_cfg);

    // ------------------------------ Cluster LIGHT ------------------------------
    esp_zb_on_off_cluster_cfg_t on_off_cfg = {
        .on_off = 0,
    };
    esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create(&on_off_cfg);

    // endpoint creation (endpoint 1)
    esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
    esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    esp_zb_cluster_list_add_on_off_cluster(cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    esp_zb_ep_list_t *endpoints_list = esp_zb_ep_list_create();

    esp_zb_endpoint_config_t endp_cfg = {
        .endpoint = 1,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID,
        .app_device_version = 1,
    };
    esp_zb_ep_list_add_ep(endpoints_list, cluster_list, endp_cfg);

    // --------------------- Other endpoint creation --------------------------
    // Creating all relay endpoints (the first one was status)
    for (int i = 0; i < 8; i++)
    {
        esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();

        // relay cluster
        esp_zb_on_off_cluster_cfg_t on_off_cfg = {
            .on_off = 0,
        };
        esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create(&on_off_cfg);
        esp_zb_cluster_list_add_on_off_cluster(cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

        // button cluster
        esp_zb_multistate_value_cluster_cfg_t switch_value_cfg = {
            .number_of_states = 7,
            .out_of_service = false,
            .present_value = CLICK_NO_CLICK,
            .status_flags = 0,
        };
        esp_zb_attribute_list_t *esp_zb_multistate_cluster = esp_zb_multistate_value_cluster_create(&switch_value_cfg);
        esp_zb_cluster_list_add_multistate_value_cluster(cluster_list, esp_zb_multistate_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

        // create endpoint
        esp_zb_endpoint_config_t endp_cfg = {
            .endpoint = i + 2,
            .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
            .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID,
            .app_device_version = 1,
        };
        esp_zb_ep_list_add_ep(endpoints_list, cluster_list, endp_cfg);
    }

    esp_zb_device_register(endpoints_list);

    // esp_zb_cluster_list_add_basic_cluster

    esp_zb_core_action_handler_register(zb_action_handler);

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

Code where I try to set "Present_value" :

static void report_button_press(uint8_t button_index, button_event_type_t event)
{
    esp_zb_lock_acquire(portMAX_DELAY);
    esp_zb_zcl_set_attribute_val(button_index + 2,
                                 ESP_ZB_ZCL_CLUSTER_ID_MULTI_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
                                 ESP_ZB_ZCL_ATTR_MULTI_VALUE_PRESENT_VALUE_ID, &event, false);
    esp_zb_lock_release();
    ESP_LOGI(TAG, "Set attribute");
}

This only set the attribute, nothing else. In Z2M, I get the following errors when trying to setup reporting : image

I also tried to send reports from the ED (code added after the "Set attribute" LOGI):

esp_zb_zcl_report_attr_cmd_t cmd = {
        .address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT,
        .clusterID = ESP_ZB_ZCL_CLUSTER_ID_MULTI_VALUE,
        .attributeID = ESP_ZB_ZCL_ATTR_MULTI_VALUE_PRESENT_VALUE_ID,
        .cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE,
        .zcl_basic_cmd.src_endpoint = button_index + 2,
    };
    esp_zb_lock_acquire(portMAX_DELAY);
    esp_err_t err = esp_zb_zcl_report_attr_cmd_req(&cmd);
    esp_zb_lock_release();

    if (err == ESP_OK)
        ESP_LOGI(TAG, "Reported button click");
    else
        ESP_LOGW(TAG, "Reporting button click failed");

This, in v 1.3.2, only return something different from ESP_OK, and thus output "Reporting button click failed". (after outputing the error code, it is 0x106, so ESP_ERR_NOT_SUPPORTED Operation or feature not supported, if I understand correctly)

The cluster specification says that PresentValue shall support reporting : image (And the same is true for Multistate Input and Output (Basic)).

The rest of the system works correctly (relays toggled from Z2M and Clicks detection from the buttons by the ESP).

Arthuret commented 2 months ago

Hello, I updated to esp-zboss-lib & esp-zigbee-lib v 1.4.0, and the PresentValue in the MultiState Value cluster is still no reportable. Is it possible to add the MultiState Input cluster and/or allow reporting of the PresentValue of these clusters, as stated in the specification ?

xieqinan commented 2 months ago

@Arthuret ,

Section 3.14.10.5.3 conflicts with Section 3.14.10.5.1, which is why we did not add reporting access to these attributes in version 1.4.0. However, there is a solution to resolve this issue in version 1.4.0:

    esp_zb_attribute_list_t *multi_value_cluster =
        esp_zb_cluster_list_get_cluster(cluster_list, ESP_ZB_ZCL_CLUSTER_ID_MULTI_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
    esp_zb_attribute_list_t *attr = multi_value_cluster;
    while (attr) {
        if (attr->attribute.id == ESP_ZB_ZCL_ATTR_MULTI_VALUE_PRESENT_VALUE_ID) {
            attr->attribute.access = multi_value_cluster->attribute.access | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING;
            break;
        }
        attr = attr->next;
    }

In Z2M, I get the following errors when trying to set up reporting:

However, from the comments, it seems that Z2M does not support reporting the PresentValue attribute.

xieqinan commented 1 month ago

@Arthuret

Use the below code to add the reporting access to the PresentValue attribute.

Does this solution work for you? Do you have any updates for this issue?

Arthuret commented 1 month ago

@xieqinan, I updated m'y code, and no longer have any errors when reporting the attribute, even when setting up reporting in z2m. I still have some tests to retrieve the value in z2m to make it useful, but as I don't have a sniffer at hand, I cannot confirm that the update is transmitted through the network. (I have a C6 devkit, but was unable to make it into a sniffer). I will update this issue as soon as I have a reporting working in z2m.