ncs-zigbee - Configuration issue with custom cluster

Hi,

I write this information for the sake of completeness. I don´t need Zigbee2MQTT support from you. Instead, support with the Zigbee firmware is required.

I´m working on an open-source Zigbee environment sensor, based on an nRF54L14, and I have a problem with a customized cluster for VOC. You can find the complete repo with the firmware here:

https://github.com/Kampi/BeeLight

I use Zigbee2MQTT for the Zigbee network, and I get a configuration error when starting the service. The Zigbee2MQTT team told me that this issue is firmware-based. You can see the ticket for this problem here:

https://github.com/Koenkk/zigbee-herdsman-converters/issues/10831#issuecomment-3568319658

I don´t understand why this issue is related to the VOC cluster only, because the cluster looks basically the same. But I don´t have a deep understanding of ZBOSS and the underlying mechanism, so I need some help to understand the issue and a potential solution. The complete VOC cluster looks like this

#ifndef ZB_ZCL_BEELIGHT_VOC_MEASUREMENT_H_
#define ZB_ZCL_BEELIGHT_VOC_MEASUREMENT_H_

#include <zcl/zb_zcl_common.h>
#include <zcl/zb_zcl_commands.h>

enum zb_zcl_voc_cluster_attr_e
{
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_ID        = 0x0000,
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID    = 0x0001,
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID    = 0x0002,
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_ID    = 0x0003,
};

/** @brief Default value for VOC Measurement cluster revision global attribute */
#define ZB_ZCL_BEELIGHT_VOC_MEASUREMENT_CLUSTER_REVISION_DEFAULT             ((zb_uint16_t)0x0001U)

/** @brief MeasuredValue attribute unknown value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_UNKNOWN                   ((zb_uint16_t)0x8000)

/** @brief MinMeasuredValue attribute minimum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_MIN_VALUE             ((zb_uint16_t)0x0000)

/** @brief MinMeasuredValue attribute maximum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_MAX_VALUE             ((zb_uint16_t)0x2710)

/** @brief MinMeasuredValue attribute invalid value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_INVALID               ((zb_uint16_t)0x8000)

/** @brief MaxMeasuredValue attribute minimum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_MIN_VALUE             ((zb_uint16_t)0x0000)

/** @brief MaxMeasuredValue attribute maximum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_MAX_VALUE             ((zb_uint16_t)0x2710)

/** @brief MaxMeasuredValue attribute invalid value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_INVALID               ((zb_uint16_t)0x8000)

/** @brief Tolerance attribute minimum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_MIN_VALUE             ((zb_uint16_t)0x0000)

/** @brief Tolerance attribute maximum value */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_MAX_VALUE             ((zb_uint16_t)0x000F)

/** @brief Default value for Value attribute */
#define ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_DEFAULT_VALUE             ((zb_uint16_t)0x0000)

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_ID(data_ptr)          \
{                                                                                               \
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_ID,                                              \
    ZB_ZCL_ATTR_TYPE_U16,                                                                       \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_REPORTING,                                \
    (ZB_ZCL_NON_MANUFACTURER_SPECIFIC),                                                         \
    (void*) data_ptr                                                                            \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID(data_ptr)      \
{                                                                                               \
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID,                                          \
    ZB_ZCL_ATTR_TYPE_U16,                                                                       \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                               \
    (ZB_ZCL_NON_MANUFACTURER_SPECIFIC),                                                         \
    (void*) data_ptr                                                                            \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID(data_ptr)      \
{                                                                                               \
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID,                                          \
    ZB_ZCL_ATTR_TYPE_U16,                                                                       \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                               \
    (ZB_ZCL_NON_MANUFACTURER_SPECIFIC),                                                         \
    (void*) data_ptr                                                                            \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_ID(data_ptr)      \
{                                                                                               \
    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_ID,                                          \
    ZB_ZCL_ATTR_TYPE_U8,                                                                        \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                               \
    (ZB_ZCL_NON_MANUFACTURER_SPECIFIC),                                                         \
    (void*) data_ptr                                                                            \
}

/** @brief Number of attributes mandatory for reporting in BeeLight VOC Measurement cluster */
#define ZB_ZCL_BEELIGHT_VOC_MEASUREMENT_REPORT_ATTR_COUNT 1

/** @brief Declare attribute list for BeeLight VOC Measurement cluster - server side
    @param attr_list - attribute list name
    @param value - pointer to variable to store MeasuredValue attribute
    @param min_value - pointer to variable to store MinMeasuredValue attribute
    @param max_value - pointer to variable to store MAxMeasuredValue attribute
    @param tolerance - pointer to variable to store Tolerance attribute
*/
#define ZB_ZCL_DECLARE_BEELIGHT_VOC_MEASUREMENT_ATTRIB_LIST(attr_list, value, min_value, max_value, tolerance)  \
    ZB_ZCL_START_DECLARE_ATTRIB_LIST_CLUSTER_REVISION(attr_list, ZB_ZCL_BEELIGHT_VOC_MEASUREMENT)               \
    ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_ID, (value))                                \
    ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID, (min_value))                        \
    ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID, (max_value))                        \
    ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_TOLERANCE_ID, (tolerance))                        \
    ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST

void zb_zcl_beelight_voc_measurement_init_server(void);
void zb_zcl_beelight_voc_measurement_init_client(void);

#define ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT_SERVER_ROLE_INIT zb_zcl_beelight_voc_measurement_init_server
#define ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT_CLIENT_ROLE_INIT zb_zcl_beelight_voc_measurement_init_client

#endif /* ZB_ZCL_BEELIGHT_VOC_MEASUREMENT_H_ */

#include "zb_common.h"

#if defined (ZB_ZCL_SUPPORT_CLUSTER_BEELIGHT_VOC_MEASUREMENT)

#include "zb_zcl.h"
#include "zb_aps.h"
#include "zcl/zb_zcl_common.h"

zb_ret_t check_value_beelight_voc_measurement_server(zb_uint16_t attr_id, zb_uint8_t endpoint, zb_uint8_t *value);
void zb_zcl_beelight_voc_measurement_write_attr_hook_server(zb_uint8_t endpoint, zb_uint16_t attr_id, zb_uint8_t *new_value, zb_uint16_t manuf_code);

void zb_zcl_beelight_voc_measurement_init_server(void)
{
    zb_zcl_add_cluster_handlers(ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT,
                                ZB_ZCL_CLUSTER_SERVER_ROLE,
                                check_value_beelight_voc_measurement_server,
                                zb_zcl_beelight_voc_measurement_write_attr_hook_server,
                                (zb_zcl_cluster_handler_t)NULL);
}

void zb_zcl_voc_measurement_init_client(void)
{
    zb_zcl_add_cluster_handlers(ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT,
                                ZB_ZCL_CLUSTER_CLIENT_ROLE,
                                (zb_zcl_cluster_check_value_t)NULL,
                                (zb_zcl_cluster_write_attr_hook_t)NULL,
                                (zb_zcl_cluster_handler_t)NULL);
}

zb_ret_t check_value_beelight_voc_measurement_server(zb_uint16_t attr_id, zb_uint8_t endpoint, zb_uint8_t *value)
{
    zb_ret_t ret = RET_OK;
    zb_int16_t val = ZB_ZCL_ATTR_GET16(value);

    TRACE_MSG(TRACE_ZCL1, "> check_value_beelight_voc_measurement, attr_id %d, val %d", (FMT__D_D, attr_id, val));

    switch (attr_id)
    {
        case ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_ID:
            if (ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_VALUE_UNKNOWN == val)
            {
                ret = RET_OK;
            }
            else
            {
                zb_zcl_attr_t *attr_desc = zb_zcl_get_attr_desc_a(endpoint,
                    ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT,
                    ZB_ZCL_CLUSTER_SERVER_ROLE,
                    ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID);
                ZB_ASSERT(attr_desc);

                ret = (ZB_ZCL_GET_ATTRIBUTE_VAL_16(attr_desc) == ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_INVALID ||
                    ZB_ZCL_GET_ATTRIBUTE_VAL_16(attr_desc) <= val)
                    ? RET_OK : RET_ERROR;

                if (ret)
                {
                    attr_desc = zb_zcl_get_attr_desc_a(endpoint,
                        ZB_ZCL_CLUSTER_ID_BEELIGHT_VOC_MEASUREMENT,
                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                        ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID);
                    ZB_ASSERT(attr_desc);

                    ret = ZB_ZCL_GET_ATTRIBUTE_VAL_16(attr_desc) == ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_INVALID ||
                            val <= ZB_ZCL_GET_ATTRIBUTE_VAL_16(attr_desc)
                        ? RET_OK : RET_ERROR;
                }
            }
            break;

        case ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_ID:
            ret = ((ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_MIN_VALUE <= val) &&
                    (val <= ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_MAX_VALUE)) ||
                    (ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MIN_VALUE_INVALID == val)
                    ? RET_OK : RET_ERROR;
            break;

        case ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_ID:
            ret = ( (ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_MIN_VALUE <= ZB_ZCL_ATTR_GET16(value)) &&
                    (ZB_ZCL_ATTR_GET16(value) <= ZB_ZCL_ATTR_BEELIGHT_VOC_MEASUREMENT_MAX_VALUE_MAX_VALUE) )
                    ? RET_OK : RET_ERROR;
            break;

        default:
            break;
    }

    TRACE_MSG(TRACE_ZCL1, "< check_value_beelight_voc_measurement ret %hd", (FMT__H, ret));

    return ret;
}

void zb_zcl_beelight_voc_measurement_write_attr_hook_server(zb_uint8_t endpoint, zb_uint16_t attr_id, zb_uint8_t *new_value, zb_uint16_t manuf_code)
{
    ZVUNUSED(new_value);
    ZVUNUSED(endpoint);
    ZVUNUSED(manuf_code);
    ZVUNUSED(attr_id);

    TRACE_MSG(TRACE_ZCL1, ">> zb_zcl_beelight_voc_measurement_write_attr_hook endpoint %hd, attr_id 0x%x, manuf_code 0x%x",
                (FMT__H_D_D, endpoint, attr_id, manuf_code));

    /* All attributes in this cluster are read-only. Do nothing */

    TRACE_MSG(TRACE_ZCL1, "<< zb_zcl_beelight_voc_measurement_write_attr_hook", (FMT__0));
}

#endif /* ZB_ZCL_SUPPORT_CLUSTER_VOC_MEASUREMENT */

As far as I understand the error message, the error happens somewhere during the configuration of this cluster. Where does this configuration happen and how can I enable debug outputs to see the issue in the firmware? Or is something wrong with the cluster definition (it´s based on the temperature measurement cluster). The current firmware doesn´t output any Zigbee-related errors yet.

Parents Reply Children
No Data
Related