I am using nrf52840-DK and trying to get the Zigbee Switch working. This is just a plain zigbee switch with no bind to light. However, this set attribute during init results in the bootloop
SET_ATTRIBUTE
The below code in switch_clusters_attr_init() which causes the issue. Removing this the zigbee device is registered successfully but does not update state
This code is at line 282 in the main.c (also attached here)
ZB_ZCL_SET_ATTRIBUTE( ENDPOINT_INVOKED, ZB_ZCL_CLUSTER_ID_ON_OFF, ZB_ZCL_CLUSTER_SERVER_ROLE, ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, (zb_uint8_t *)&on, ZB_FALSE);
main.c
#include <zephyr/types.h>
#include <zephyr.h>
#include <device.h>
#include <soc.h>
#include <drivers/pwm.h>
#include <logging/log.h>
#include <dk_buttons_and_leds.h>
#include <settings/settings.h>
#include <zboss_api.h>
#include <zboss_api_addons.h>
#include <zb_mem_config_med.h>
#include <zigbee/zigbee_app_utils.h>
#include <zigbee/zigbee_error_handler.h>
#include <zigbee/zigbee_zcl_scenes.h>
#include <zb_nrf_platform.h>
/* Switch endpoint */
#define HA_SWITCH_ENDPOINT 12
/* Version of the application software (1 byte). */
#define SWITCH_INIT_BASIC_APP_VERSION 01
/* Version of the implementation of the Zigbee stack (1 byte). */
#define SWITCH_INIT_BASIC_STACK_VERSION 10
/* Version of the hardware of the device (1 byte). */
#define SWITCH_INIT_BASIC_HW_VERSION 11
/* Manufacturer name (32 bytes). */
#define SWITCH_INIT_BASIC_MANUF_NAME "DongleNordic"
/* Model number assigned by manufacturer (32-bytes long string). */
#define SWITCH_INIT_BASIC_MODEL_ID "DongleSwitch"
/* First 8 bytes specify the date of manufacturer of the device
* in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific.
*/
#define SWITCH_INIT_BASIC_DATE_CODE "202201207777"
/* Type of power sources available for the device.
* For possible values see section 3.2.2.2.8 of ZCL specification.
*/
#define SWITCH_INIT_BASIC_POWER_SOURCE ZB_ZCL_BASIC_POWER_SOURCE_BATTERY
/* Describes the physical location of the device (16 bytes).
* May be modified during commisioning process.
*/
#define SWITCH_INIT_BASIC_LOCATION_DESC "Home"
/* Describes the type of physical environment.
* For possible values see section 3.2.2.2.10 of ZCL specification.
*/
#define SWITCH_INIT_BASIC_PH_ENV ZB_ZCL_BASIC_ENV_UNSPECIFIED
#define TOGGLE_SWITCH DK_BTN3_MSK
/* Nordic PWM nodes don't have flags cells in their specifiers, so
* this is just future-proofing.
*/
#define FLAGS_OR_ZERO(node) \
COND_CODE_1(DT_PHA_HAS_CELL(node, pwms, flags), \
(DT_PWMS_FLAGS(node)), (0))
#ifndef ZB_ED_ROLE
#error Define ZB_END_DEVICE_ROLE to compile enddevice source code.
#endif
static void on_off_set_value(zb_bool_t on, zb_uint8_t endpoint_invoked);
static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off);
LOG_MODULE_REGISTER(app);
/**
* Placeholder for the bulb context
* Stores all settings and static values.
**/
typedef struct
{
zb_zcl_basic_attrs_ext_t basic_attr;
zb_zcl_identify_attrs_t identify_attr;
zb_zcl_scenes_attrs_t scenes_attr;
zb_zcl_groups_attrs_t groups_attr;
zb_zcl_on_off_attrs_t on_off_attr;
} switch_device_ctx_t;
/* Zigbee device application context storage. */
static switch_device_ctx_t dev_ctx;
/////////// DECLARATION FOR FIRST ENDPOINT - START /////////////////////////////////////
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
identify_attr_list,
&dev_ctx.identify_attr.identify_time);
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(
basic_attr_list,
&dev_ctx.basic_attr.zcl_version,
&dev_ctx.basic_attr.app_version,
&dev_ctx.basic_attr.stack_version,
&dev_ctx.basic_attr.hw_version,
dev_ctx.basic_attr.mf_name,
dev_ctx.basic_attr.model_id,
dev_ctx.basic_attr.date_code,
&dev_ctx.basic_attr.power_source,
dev_ctx.basic_attr.location_id,
&dev_ctx.basic_attr.ph_env,
dev_ctx.basic_attr.sw_ver);
/* On/Off cluster attributes additions data */
ZB_ZCL_DECLARE_ON_OFF_ATTRIB_LIST(
on_off_attr_list,
&dev_ctx.on_off_attr.on_off);
ZB_HA_DECLARE_ON_OFF_SWITCH_CLUSTER_LIST(
switch_clusters,
on_off_attr_list,
basic_attr_list,
identify_attr_list
);
ZB_HA_DECLARE_ON_OFF_SWITCH_EP(
switch_ep,
HA_SWITCH_ENDPOINT,
switch_clusters);
/////////// DECLARATION FOR FIRST ENDPOINT - END /////////////////////////////////////
/**
* Declares the context of single endpoint
*
**/
ZB_HA_DECLARE_ON_OFF_SWITCH_CTX(switch_ctx, switch_ep);
/**@brief Callback for button events.
*
* @param[in] button_state Bitmask containing buttons state.
* @param[in] has_changed Bitmask containing buttons
* that have changed their state.
*/
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
zb_ret_t zb_err_code;
zb_uint16_t cmd_id;
// user_input_indicate();
/* Calculate bitmask of buttons that are pressed
* and have changed their state.
*/
uint32_t buttons = button_state & has_changed;
if (buttons & TOGGLE_SWITCH)
{
LOG_INF("Current LED setting is %d", dev_ctx.on_off_attr.on_off);
if(dev_ctx.on_off_attr.on_off)
{
// on_off_set_value(ZB_FALSE, HA_BUTTON_ENDPOINT);
cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
}
else
{
// on_off_set_value(ZB_TRUE, HA_BUTTON_ENDPOINT);
cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
}
zb_err_code = zb_buf_get_out_delayed_ext(switch_send_on_off, cmd_id, 0);
ZB_ERROR_CHECK(zb_err_code);
LOG_INF("Toggling Completed");
}
}
/**@brief Function for initializing LEDs and Buttons. */
static void configure_gpio(void)
{
int err;
err = dk_buttons_init(button_changed);
if (err) {
LOG_ERR("Cannot init buttons (err: %d)", err);
}
}
// /**
// * Sets the respective LEDs ON or OFF depending upon the ENDPOINT INVOKED
// * @brief Function for turning ON/OFF the light bulb.
// *
// * @param[in] on Boolean light bulb state.
// */
// static void on_off_set_value(zb_bool_t on, zb_uint8_t ENDPOINT_INVOKED)
// {
// LOG_INF("Set ON/OFF value: %i", on);
// ZB_ZCL_SET_ATTRIBUTE(
// ENDPOINT_INVOKED,
// ZB_ZCL_CLUSTER_ID_ON_OFF,
// ZB_ZCL_CLUSTER_SERVER_ROLE,
// ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
// (zb_uint8_t *)&on,
// ZB_FALSE);
// }
/**@brief Function for sending ON/OFF requests to the network / co-ordinator.
*
* @param[in] bufid Non-zero reference to Zigbee stack buffer that will be
* used to construct on/off request.
* @param[in] cmd_id ZCL command id.
*/
static void switch_send_on_off(zb_bufid_t bufid, zb_uint16_t cmd_id)
{
LOG_INF("Send ON/OFF command: %d", cmd_id);
zb_uint16_t coordinator_address = 0x0000;
// switch_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;
// LOG_INF("Testpoint1:");
// ZB_ZCL_SET_ATTRIBUTE(HA_BUTTON_ENDPOINT,
// ZB_ZCL_CLUSTER_ID_ON_OFF,
// ZB_ZCL_CLUSTER_SERVER_ROLE,
// ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
// (zb_uint8_t *)&switch_ctx.on_off_attr.on_off,
// ZB_FALSE);
LOG_INF("Testpoint2:");
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
coordinator_address,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
HA_SWITCH_ENDPOINT,
HA_SWITCH_ENDPOINT,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
LOG_INF("Send ON/OFF command Completed: %d", cmd_id);
}
/**@brief Function for initializing all clusters attributes.
*/
static void switch_clusters_attr_init(void)
{
/* Basic cluster attributes data */
dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
dev_ctx.basic_attr.app_version = SWITCH_INIT_BASIC_APP_VERSION;
dev_ctx.basic_attr.stack_version = SWITCH_INIT_BASIC_STACK_VERSION;
dev_ctx.basic_attr.hw_version = SWITCH_INIT_BASIC_HW_VERSION;
/* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte
* should contain string length without trailing zero.
*
* For example "test" string wil be encoded as:
* [(0x4), 't', 'e', 's', 't']
*/
ZB_ZCL_SET_STRING_VAL(
dev_ctx.basic_attr.mf_name,
SWITCH_INIT_BASIC_MANUF_NAME,
ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_MANUF_NAME));
ZB_ZCL_SET_STRING_VAL(
dev_ctx.basic_attr.model_id,
SWITCH_INIT_BASIC_MODEL_ID,
ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_MODEL_ID));
ZB_ZCL_SET_STRING_VAL(
dev_ctx.basic_attr.date_code,
SWITCH_INIT_BASIC_DATE_CODE,
ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_DATE_CODE));
dev_ctx.basic_attr.power_source = SWITCH_INIT_BASIC_POWER_SOURCE;
ZB_ZCL_SET_STRING_VAL(
dev_ctx.basic_attr.location_id,
SWITCH_INIT_BASIC_LOCATION_DESC,
ZB_ZCL_STRING_CONST_SIZE(SWITCH_INIT_BASIC_LOCATION_DESC));
dev_ctx.basic_attr.ph_env = SWITCH_INIT_BASIC_PH_ENV;
/* Identify cluster attributes data. */
dev_ctx.identify_attr.identify_time =
ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
/* On/Off cluster attributes data. */
dev_ctx.on_off_attr.on_off = ZB_FALSE;
ZB_ZCL_SET_ATTRIBUTE(
HA_SWITCH_ENDPOINT,
ZB_ZCL_CLUSTER_ID_ON_OFF,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
(zb_uint8_t *)&dev_ctx.on_off_attr.on_off,
ZB_FALSE);
}
/**@brief Callback function for handling ZCL commands.
*
* @param[in] bufid Reference to Zigbee stack buffer
* used to pass received data.
*/
static void zcl_device_cb(zb_bufid_t bufid)
{
zb_uint8_t cluster_id;
zb_uint8_t attr_id;
zb_uint8_t endpoint_invoked;
zb_zcl_device_callback_param_t *device_cb_param =
ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
endpoint_invoked = device_cb_param->endpoint;
LOG_INF("%s id %hd", __func__, device_cb_param->device_cb_id);
LOG_INF("EndPoint Called is %d ", endpoint_invoked);
/* Set default response value. */
device_cb_param->status = RET_OK;
LOG_INF("ZB Callback started %c", bufid);
switch (device_cb_param->device_cb_id)
{
case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
LOG_INF("Inside the ZB_ZCL_SET_ATTR_VALUE_CB_ID");
cluster_id = device_cb_param->cb_param.set_attr_value_param.cluster_id;
attr_id = device_cb_param->cb_param.set_attr_value_param.attr_id;
if (cluster_id == ZB_ZCL_CLUSTER_ID_ON_OFF)
{
uint8_t value = device_cb_param->cb_param.set_attr_value_param.values.data8;
LOG_INF("on/off attribute setting to %hd", value);
if (attr_id == ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID)
{
// on_off_set_value((zb_bool_t)value);
//on_off_set_value((zb_bool_t)value, endpoint_invoked);
LOG_INF("ON INVOKED:");
}
}
else
{
/* Other clusters can be processed here */
LOG_INF("Unhandled cluster attribute id: %d",
cluster_id);
}
break;
default:
device_cb_param->status = RET_ERROR;
break;
}
LOG_INF("%s status: %hd", __func__, device_cb_param->status);
}
/**@brief Zigbee stack event handler.
*
* @param[in] bufid Reference to the Zigbee stack buffer
* used to pass signal.
*/
void zboss_signal_handler(zb_bufid_t bufid)
{
/* No application-specific behavior is required.
* Call default signal handler.
*/
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
/* All callbacks should either reuse or free passed buffers.
* If bufid == 0, the buffer is invalid (not passed).
*/
if (bufid) {
zb_buf_free(bufid);
}
}
void error(void)
{
while (true) {
/* Spin forever */
k_sleep(K_MSEC(1000));
}
}
void main(void)
{
int err;
LOG_INF("Starting Zigbee Switch example");
/* Initialize */
configure_gpio();
err = settings_subsys_init();
if (err) {
LOG_ERR("settings initialization failed");
}
LOG_INF("Registering Device");
/* Register callback for handling ZCL commands. */
ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
LOG_INF("Setting Switch Context");
/* Register dimmer switch device context (all the endpoints). */
ZB_AF_REGISTER_DEVICE_CTX(&switch_ctx);
switch_clusters_attr_init();
/* Initialize ZCL scene table */
// zcl_scenes_init();
LOG_INF("ZCL scenes initiated");
/* Settings should be loaded after zcl_scenes_init */
err = settings_load();
if (err) {
LOG_ERR("settings loading failed");
}
/* Start Zigbee default thread */
zigbee_enable();
LOG_INF("Zigbee Switch example started");
while (1) {
// k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
}
}
Debug Terminal
