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.



