Zigbee randomly fails after connecting to the network

Using a slightly modified version of the Zigbee Light Bulb sample app from the current samples compiled using nRF Connect for VSCode on a Mac and programmed to a nRF52840DK board I find that the device will connect to the network then, very quickly, it will stop working and responding to commands sent from the coordinator.

I have tried two different coordinators, both connected to a Home Assistant instance running on a Raspberry Pi CM5. One is a Nortek stick with Zigbee and ZWave on it and the other is a Sonoff Zigbee 3.0 stick. Both behave in the same way. The Zigbee network has quite a few devices, 110 including the test board, so I tried in a pristine network, again using Home Assistant with the Nortek coordinator but with only the nRF52840 as a single client. This appears to be stable, at least for several hours during testing and observation. It is only in the busy network that there seems to be an error.

I have attached a Wireshark PCAP file captured via a nRF52840 sniffer during network inclusion of the test board.

Logging the running code shows that immediately after joining I start seeing 'No route available' errors. These continue until the board is reset.

*** Using Zephyr OS v3.7.99-aa34a5632971 ***
[00:00:00.005,706] <inf> app: Starting Zigbee R23 Light Bulb example
[00:00:00.013,549] <inf> fs_nvs: 2 Sectors of 4096 bytes
[00:00:00.013,946] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:00.014,312] <inf> fs_nvs: data wra: 0, 0
[00:00:00.015,045] <inf> app: Set level value: 255
[00:00:00.027,587] <inf> app: Zigbee R23 Light Bulb example started
[00:00:00.029,510] <inf> app: Zigbee signal 23
[00:00:00.029,876] <inf> zigbee_app_utils: Zigbee signal handler: signal 23, status -1
[00:00:00.030,364] <inf> zigbee_app_utils: Production configuration is not present or invalid (status: -1)
[00:00:00.031,372] <inf> app: Zigbee signal 1
[00:00:00.031,707] <inf> zigbee_app_utils: Zigbee signal handler: signal 1, status 0
[00:00:00.032,196] <inf> zigbee_app_utils: Zigbee stack initialized
[00:00:00.073,272] <inf> zigbee_app_utils: Zigbee signal handler: signal 59, status 0
[00:00:00.075,897] <inf> zigbee_app_utils: Zigbee signal handler: signal 6, status 0
[00:00:00.076,568] <inf> zigbee_app_utils: Joined network successfully on reboot signal (Extended PAN ID: bf9301739ee2a580, PAN ID: 0x75ae)
[00:00:10.181,030] <inf> zigbee_app_utils: Zigbee signal handler: signal 52, status 0
[00:00:10.181,488] <inf> zigbee_app_utils: No route available
[00:00:12.204,620] <inf> zigbee_app_utils: Zigbee signal handler: signal 52, status 0
[00:00:12.205,078] <inf> zigbee_app_utils: No route available
[00:00:16.203,918] <inf> zigbee_app_utils: Zigbee signal handler: signal 52, status 0
[00:00:16.204,406] <inf> zigbee_app_utils: No route available

Occasionally, it will complete the interview with home Assistant and I can turn on and off the LED and set its brightness a few times but it quickly fails in the same way and becomes unresponsive.

Here is the source code to main.c. As you will see the changes from the sample are minimal...

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/** @file
 *
 * @brief Simple Zigbee light bulb implementation.
 */

#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <soc.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/logging/log.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/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>
#include "zb_dimmable_light.h"

#define RUN_STATUS_LED                  DK_LED1
#define RUN_LED_BLINK_INTERVAL          1000

/* LED indicating that light switch successfully joind Zigbee network. */
#define ZIGBEE_NETWORK_STATE_LED        DK_LED3

/* LED immitaing dimmable light bulb - define for informational
 * purposes only.
 */
#define BULB_LED                        DK_LED4


/* Device endpoint, used to receive light controlling commands. */
#define DIMMABLE_LIGHT_ENDPOINT         10

/* Version of the application software (1 byte). */
#define BULB_INIT_BASIC_APP_VERSION     01

/* Version of the implementation of the Zigbee stack (1 byte). */
#define BULB_INIT_BASIC_STACK_VERSION   10

/* Version of the hardware of the device (1 byte). */
#define BULB_INIT_BASIC_HW_VERSION      11

/* Manufacturer name (32 bytes). */
#define BULB_INIT_BASIC_MANUF_NAME      "Nordic"

/* Model number assigned by manufacturer (32-bytes long string). */
#define BULB_INIT_BASIC_MODEL_ID        "Dimable_Light_v0.1"

/* First 8 bytes specify the date of manufacturer of the device
 * in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific.
 */
#define BULB_INIT_BASIC_DATE_CODE       "20200329"

/* Type of power sources available for the device.
 * For possible values see section 3.2.2.2.8 of ZCL specification.
 */
#define BULB_INIT_BASIC_POWER_SOURCE    ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE

/* Describes the physical location of the device (16 bytes).
 * May be modified during commissioning process.
 */
#define BULB_INIT_BASIC_LOCATION_DESC   "Office desk"

/* Describes the type of physical environment.
 * For possible values see section 3.2.2.2.10 of ZCL specification.
 */
#define BULB_INIT_BASIC_PH_ENV          ZB_ZCL_BASIC_ENV_UNSPECIFIED

/* Button used to enter the Bulb into the Identify mode. */
#define IDENTIFY_MODE_BUTTON            DK_BTN4_MSK

/* Use onboard led4 to act as a light bulb.
 * The app.overlay file has this at node label "pwm_led3" in /pwmleds.
 */
#define PWM_DK_LED_NODE                DT_NODELABEL(pwm_led3)

#if DT_NODE_HAS_STATUS(PWM_DK_LED_NODE, okay)
static const struct pwm_dt_spec led_pwm = PWM_DT_SPEC_GET(PWM_DK_LED_NODE);
#else
#error "Choose supported PWM driver"
#endif

/* Led PWM period, calculated for 100 Hz signal - in microseconds. */
#define LED_PWM_PERIOD_US               (USEC_PER_SEC / 100U)

#ifndef ZB_ROUTER_ROLE
#error Define ZB_ROUTER_ROLE to compile router source code.
#endif

/* Button to start Factory Reset */
#define FACTORY_RESET_BUTTON IDENTIFY_MODE_BUTTON

LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);

/* Main application customizable 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;
	zb_zcl_level_control_attrs_t level_control_attr;
} bulb_device_ctx_t;

/* Zigbee device application context storage. */
static bulb_device_ctx_t dev_ctx;
static bool b_joined = false;

ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
	identify_attr_list,
	&dev_ctx.identify_attr.identify_time);

ZB_ZCL_DECLARE_GROUPS_ATTRIB_LIST(
	groups_attr_list,
	&dev_ctx.groups_attr.name_support);

ZB_ZCL_DECLARE_SCENES_ATTRIB_LIST(
	scenes_attr_list,
	&dev_ctx.scenes_attr.scene_count,
	&dev_ctx.scenes_attr.current_scene,
	&dev_ctx.scenes_attr.current_group,
	&dev_ctx.scenes_attr.scene_valid,
	&dev_ctx.scenes_attr.name_support);

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_ZCL_DECLARE_LEVEL_CONTROL_ATTRIB_LIST(
	level_control_attr_list,
	&dev_ctx.level_control_attr.current_level,
	&dev_ctx.level_control_attr.remaining_time);

ZB_DECLARE_DIMMABLE_LIGHT_CLUSTER_LIST(
	dimmable_light_clusters,
	basic_attr_list,
	identify_attr_list,
	groups_attr_list,
	scenes_attr_list,
	on_off_attr_list,
	level_control_attr_list);


ZB_DECLARE_DIMMABLE_LIGHT_EP(
	dimmable_light_ep,
	DIMMABLE_LIGHT_ENDPOINT,
	dimmable_light_clusters);

ZBOSS_DECLARE_DEVICE_CTX_1_EP(
	dimmable_light_ctx,
	dimmable_light_ep);

/**@brief Starts identifying the device.
 *
 * @param  bufid  Unused parameter, required by ZBOSS scheduler API.
 */
static void start_identifying(zb_bufid_t bufid)
{
	ZVUNUSED(bufid);

	if (ZB_JOINED()) {
		/* Check if endpoint is in identifying mode,
		 * if not, put desired endpoint in identifying mode.
		 */
		if (dev_ctx.identify_attr.identify_time ==
		    ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE) {

			zb_ret_t zb_err_code = zb_bdb_finding_binding_target(
				DIMMABLE_LIGHT_ENDPOINT);

			if (zb_err_code == RET_OK) {
				LOG_INF("Enter identify mode");
			} else if (zb_err_code == RET_INVALID_STATE) {
				LOG_WRN("RET_INVALID_STATE - Cannot enter identify mode");
			} else {
				ZB_ERROR_CHECK(zb_err_code);
			}
		} else {
			LOG_INF("Cancel identify mode");
			zb_bdb_finding_binding_target_cancel();
		}
	} else {
		LOG_WRN("Device not in a network - cannot enter identify mode");
	}
}

/**@brief Callback for button events.
 *
 * @param[in]   button_state  Bitmask containing the state of the buttons.
 * @param[in]   has_changed   Bitmask containing buttons that have changed their state.
 */
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	if (IDENTIFY_MODE_BUTTON & has_changed) {
		if (IDENTIFY_MODE_BUTTON & button_state) {
			/* Button changed its state to pressed */
		} else {
			/* Button changed its state to released */
			if (was_factory_reset_done()) {
				/* The long press was for Factory Reset */
				LOG_DBG("After Factory Reset - ignore button release");
			} else   {
				/* Button released before Factory Reset */

				/* Start identification mode */
				ZB_SCHEDULE_APP_CALLBACK(start_identifying, 0);
			}
		}
	}

	check_factory_reset_button(button_state, has_changed);
}

/**@brief Function for initializing additional PWM leds. */
static void pwm_led_init(void)
{
	if (!device_is_ready(led_pwm.dev)) {
		LOG_ERR("Error: PWM device %s is not ready",
			led_pwm.dev->name);
	}
}

/**@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);
	}

	err = dk_leds_init();
	if (err) {
		LOG_ERR("Cannot init LEDs (err: %d)", err);
	}

	pwm_led_init();
}

/**@brief Sets brightness of bulb luminous executive element
 *
 * @param[in] brightness_level Brightness level, allowed values 0 ... 255,
 *                             0 - turn off, 255 - full brightness.
 */
static void light_bulb_set_brightness(zb_uint8_t brightness_level)
{
	uint32_t pulse = brightness_level * LED_PWM_PERIOD_US / 255U;

	if (pwm_set_dt(&led_pwm, PWM_USEC(LED_PWM_PERIOD_US), PWM_USEC(pulse))) {
		LOG_ERR("Pwm led 4 set fails:\n");
		return;
	}
}

/**@brief Function for setting the light bulb brightness.
 *
 * @param[in] new_level   Light bulb brightness value.
 */
static void level_control_set_value(zb_uint16_t new_level)
{
	LOG_INF("Set level value: %i", new_level);

	ZB_ZCL_SET_ATTRIBUTE(
		DIMMABLE_LIGHT_ENDPOINT,
		ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,
		ZB_ZCL_CLUSTER_SERVER_ROLE,
		ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID,
		(zb_uint8_t *)&new_level,
		ZB_FALSE);

	light_bulb_set_brightness(new_level);
}

/**@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)
{
	LOG_INF("Set ON/OFF value: %i", on);

	ZB_ZCL_SET_ATTRIBUTE(
		DIMMABLE_LIGHT_ENDPOINT,
		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);

	if (on) {
		light_bulb_set_brightness(dev_ctx.level_control_attr.current_level);
	} else {
		light_bulb_set_brightness(0U);
	}
}

/**@brief Function to toggle the identify LED - BULB_LED is used for this.
 *
 * @param  bufid  Unused parameter, required by ZBOSS scheduler API.
 */
static void toggle_identify_led(zb_bufid_t bufid)
{
	static int blink_status;

	light_bulb_set_brightness(((++blink_status) % 2) ? (255U) : (0U));
	ZB_SCHEDULE_APP_ALARM(toggle_identify_led, bufid, ZB_MILLISECONDS_TO_BEACON_INTERVAL(100));
}

/**@brief Function to handle identify notification events on the first endpoint.
 *
 * @param  bufid  Unused parameter, required by ZBOSS scheduler API.
 */
static void identify_cb(zb_bufid_t bufid)
{
	zb_ret_t zb_err_code;

	if (bufid) {
		/* Schedule a self-scheduling function that will toggle the LED. */
		ZB_SCHEDULE_APP_CALLBACK(toggle_identify_led, bufid);
	} else {
		/* Cancel the toggling function alarm and restore current Zigbee LED state. */
		zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(toggle_identify_led, ZB_ALARM_ANY_PARAM);
		ZVUNUSED(zb_err_code);

		if (dev_ctx.on_off_attr.on_off) {
			light_bulb_set_brightness(dev_ctx.level_control_attr.current_level);
		} else {
			light_bulb_set_brightness(0U);
		}
	}
}

/**@brief Function for initializing all clusters attributes.
 */
static void bulb_clusters_attr_init(void)
{
	/* Basic cluster attributes data */
	dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
	dev_ctx.basic_attr.app_version = BULB_INIT_BASIC_APP_VERSION;
	dev_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
	dev_ctx.basic_attr.hw_version = BULB_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 will be encoded as:
	 *   [(0x4), 't', 'e', 's', 't']
	 */
	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.mf_name,
		BULB_INIT_BASIC_MANUF_NAME,
		ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MANUF_NAME));

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.model_id,
		BULB_INIT_BASIC_MODEL_ID,
		ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MODEL_ID));

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.date_code,
		BULB_INIT_BASIC_DATE_CODE,
		ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));

	dev_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;

	ZB_ZCL_SET_STRING_VAL(
		dev_ctx.basic_attr.location_id,
		BULB_INIT_BASIC_LOCATION_DESC,
		ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));

	dev_ctx.basic_attr.ph_env = BULB_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_bool_t)ZB_ZCL_ON_OFF_IS_ON;

	dev_ctx.level_control_attr.current_level =
		ZB_ZCL_LEVEL_CONTROL_LEVEL_MAX_VALUE;
	dev_ctx.level_control_attr.remaining_time =
		ZB_ZCL_LEVEL_CONTROL_REMAINING_TIME_DEFAULT_VALUE;

	ZB_ZCL_SET_ATTRIBUTE(
		DIMMABLE_LIGHT_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);

	ZB_ZCL_SET_ATTRIBUTE(
		DIMMABLE_LIGHT_ENDPOINT,
		ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,
		ZB_ZCL_CLUSTER_SERVER_ROLE,
		ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID,
		(zb_uint8_t *)&dev_ctx.level_control_attr.current_level,
		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_zcl_device_callback_param_t  *device_cb_param =
		ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);

	LOG_INF("%s id %hd", __func__, device_cb_param->device_cb_id);

	/* Set default response value. */
	device_cb_param->status = RET_OK;

	switch (device_cb_param->device_cb_id) {
	case ZB_ZCL_LEVEL_CONTROL_SET_VALUE_CB_ID:
		LOG_INF("Level control setting to %d",
			device_cb_param->cb_param.level_control_set_value_param
			.new_value);
		level_control_set_value(
			device_cb_param->cb_param.level_control_set_value_param
			.new_value);
		break;

	case 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);
			}
		} else if (cluster_id == ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL) {
			uint16_t value = device_cb_param->cb_param.
					 set_attr_value_param.values.data16;

			LOG_INF("level control attribute setting to %hd",
				value);
			if (attr_id ==
			    ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID) {
				level_control_set_value(value);
			}
		} else {
			/* Other clusters can be processed here */
			LOG_INF("Unhandled cluster attribute id: %d",
				cluster_id);
			device_cb_param->status = RET_NOT_IMPLEMENTED;
		}
		break;

	default:
		if (zcl_scenes_cb(bufid) == ZB_FALSE) {
			device_cb_param->status = RET_NOT_IMPLEMENTED;
		}
		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)
{
	/* Update network status LED. */
//	zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);

	zb_zdo_app_signal_hdr_t *p_sg_p = NULL;
	zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &p_sg_p);
	zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);

	switch (sig) {
	case ZB_BDB_SIGNAL_DEVICE_REBOOT:
	/* fall-through */
	case ZB_BDB_SIGNAL_STEERING:
		if (status == RET_OK) {
			b_joined = true;
		} else {
			b_joined = false;
		}
		break;

	case ZB_ZDO_SIGNAL_LEAVE:
		/* Update network status LED */
		b_joined = false;
		break;

	case ZB_COMMON_SIGNAL_CAN_SLEEP:
	case ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS:
		/* Permit join status changed */
		break;

	case ZB_NLME_STATUS_INDICATION:
		// switch (status) {
		// case ZB_NWK_COMMAND_STATUS_NO_ROUTE_AVAILABLE:
		// 	LOG_INF("No route available");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_TREE_LINK_FAILURE:
		// 	LOG_INF("Tree link failure");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_NONE_TREE_LINK_FAILURE:
		//     LOG_INF("None-tree link failure");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_LOW_BATTERY_LEVEL:
		//     LOG_INF("Low battery level");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_NO_ROUTING_CAPACITY:
		//     LOG_INF("No routing capacity");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_NO_INDIRECT_CAPACITY:
		//     LOG_INF("No indirect capacity");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_INDIRECT_TRANSACTION_EXPIRY:
		//     LOG_INF("Indirect transaction expiry");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_TARGET_DEVICE_UNAVAILABLE:
		//     LOG_INF("Target device unavailable");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_TARGET_ADDRESS_UNALLOCATED:
		//     LOG_INF("Target address unallocated");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_PARENT_LINK_FAILURE:
		//     LOG_INF("Parent link failure");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_VALIDATE_ROUTE:
		//     LOG_INF("Validate route");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_SOURCE_ROUTE_FAILURE:
		//     LOG_INF("Source route failure");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_MANY_TO_ONE_ROUTE_FAILURE:
		// 	LOG_INF("Many-to-one route failure");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_ADDRESS_CONFLICT:
		//     LOG_INF("Address conflict");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_VERIFY_ADDRESS:
		//     LOG_INF("Verify address");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_PAN_IDENTIFIER_UPDATE:
		//     LOG_INF("Pan ID update");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_NETWORK_ADDRESS_UPDATE:
		//     LOG_INF("Network address update");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_BAD_FRAME_COUNTER:
		//     LOG_INF("Bad frame counter");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_BAD_KEY_SEQUENCE_NUMBER:
		//     LOG_INF("Bad key sequence number");
		// 	break;
		// case  ZB_NWK_COMMAND_STATUS_UNKNOWN_COMMAND:
		//     LOG_INF("Command received is not known *//** @}");
		// 	break;
		// default:
		// 	LOG_INF("Unknown NLME status indication: %d", status);
		// 	break;
		// };
		break;
	default:
		LOG_INF("Zigbee signal %d", sig);
		break;
	}

	/* 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);
	}
}

int main(void)
{
	int blink_status = 0;
	int err;

	LOG_INF("Starting Zigbee R23 Light Bulb example");

	/* Initialize */
	configure_gpio();
	err = settings_subsys_init();
	if (err) {
		LOG_ERR("settings initialization failed");
	}
	register_factory_reset_button(FACTORY_RESET_BUTTON);

	/* Register callback for handling ZCL commands. */
	ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

	/* Register dimmer switch device context (endpoints). */
	ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);

	bulb_clusters_attr_init();
	level_control_set_value(dev_ctx.level_control_attr.current_level);

	/* Register handler to identify notifications. */
	ZB_AF_SET_IDENTIFY_NOTIFICATION_HANDLER(DIMMABLE_LIGHT_ENDPOINT, identify_cb);

	/* Initialize ZCL scene table */
	zcl_scenes_init();

	/* 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 R23 Light Bulb example started");

	while (1) {
		if (b_joined) {
			dk_set_led(RUN_STATUS_LED, 0);
		} else {
			dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
		}
		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
	}
}

and the prj.conf file...

#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

CONFIG_NCS_SAMPLES_DEFAULTS=y

CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_SERIAL=y
CONFIG_GPIO=y
CONFIG_PWM=y

# Make sure printk is not printing to the UART console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_MAIN_THREAD_PRIORITY=7

CONFIG_ZIGBEE_ADD_ON=y
CONFIG_ZIGBEE_APP_UTILS=y
CONFIG_ZIGBEE_ROLE_ROUTER=y

# Enable DK LED and Buttons library
CONFIG_DK_LIBRARY=y

# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

# Networking
CONFIG_NET_IPV6=n
CONFIG_NET_IP_ADDR_CHECK=n
CONFIG_NET_UDP=n

# Scene extension
CONFIG_ZIGBEE_SCENES=y

CONFIG_ZIGBEE_CHANNEL_SELECTION_MODE_MULTI=y
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_LOG_BACKEND_UART=n
CONFIG_NRF_802154_RX_BUFFERS=24

Parents
  • Hello,

    Using a slightly modified version of the Zigbee Light Bulb sample app

    Does the same happen if you use the unmodified version of the sample?

    What NCS (and addon?) version are you using?

    Does it also happen if you use a couple of DKs, and run one board running light bulb, one network coordinator, and one light switch? Can you then keep it running "forever"?

    Best regards,

    Edvin

  • I cannot use an unmodified version of the light bulb sample because a. you do not enable debug logging in the samples and b. you fix the channel to 16. The only relevant changes I made were to enable multiple channels and enable RTT logging.

    I am using the latest version of NCS, installed 5 days ago. V3.1.1 with Zigbee 2.9.2

    I can run the same code with a Nortek coordinator (exactly the same host software and coordinator) with no other devices included. This appears to run indefinitely (more than 6 hours at least) without a problem. If I connect it to the main network with 109 other devices active it fails withing a minute or so, most times not even completing the interview process to get registered with the host.

    I only have one DK and one dongle available so I cannot test it in the full demo setup with switch, bulb and coordinator but since it works just fine with no other devices in a HomeAssistant instance and Nortek coordinator I cannot imagine what difference I am likely to observe. It must be something coming from another device connected tot he hub but I do not know where to start looking. In the end, it should not be sensitive to other devices or it is a complete non-starter for a production product.

  • Hello,

    Can you please try to generate a ZBOSS trace? To do so, please add this to your devicetree .overlay file:

    chosen {
        ncs,zboss-trace-uart = &uart1;
    };

    and add this to your prj.conf:

    CONFIG_ZIGBEE_ENABLE_TRACES=y
    CONFIG_ZBOSS_TRACE_MASK=0x00000141
    CONFIG_ZBOSS_TRACE_LOG_LEVEL_INF=y
    CONFIG_ZBOSS_TRACE_BINARY_LOGGING=y
    CONFIG_ZBOSS_TRACE_LOGGER_BUFFER_SIZE=65536

    What does it print? Can you please save it to a file and upload it here?

    Best regards,

    Edvin

Reply
  • Hello,

    Can you please try to generate a ZBOSS trace? To do so, please add this to your devicetree .overlay file:

    chosen {
        ncs,zboss-trace-uart = &uart1;
    };

    and add this to your prj.conf:

    CONFIG_ZIGBEE_ENABLE_TRACES=y
    CONFIG_ZBOSS_TRACE_MASK=0x00000141
    CONFIG_ZBOSS_TRACE_LOG_LEVEL_INF=y
    CONFIG_ZBOSS_TRACE_BINARY_LOGGING=y
    CONFIG_ZBOSS_TRACE_LOGGER_BUFFER_SIZE=65536

    What does it print? Can you please save it to a file and upload it here?

    Best regards,

    Edvin

Children
  • I recreated the Zigbee samples folder and edited the sample light bulb project. The only thing I changed was the kconfig option to use multiple channels when searching for a network. The sample connected then immediately stopped working.

    I added the line ncs,zboss-trace-uart = &uart1; to the overlay file for the nRF52840DK board and then added the CONFIG lines to the end of the prj.conf file.

    When I try to build the project using the pristine build option I get the following errors which I do not know how to address...

    In file included from /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/include/zephyr/toolchain/gcc.h:98,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/include/zephyr/toolchain.h:50,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/lib/libc/minimal/include/string.h:13,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/lib/zboss/include/osif/zb_config_platform.h:12,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/lib/zboss/include/osif/zb_vendor.h:21,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/lib/zboss/include/zb_config.h:58,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/lib/zboss/include/zb_channel_page.h:46,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/lib/zboss/include/zboss_api.h:47,
                     from /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/subsys/osif/zb_nrf_serial_logger.c:7:
    /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/include/zephyr/device.h:92:41: error: '__device_dts_ord_119' undeclared here (not in a function); did you mean '__device_dts_ord_19'?
       92 | #define DEVICE_NAME_GET(dev_id) _CONCAT(__device_, dev_id)
          |                                         ^~~~~~~~~
    /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/include/zephyr/device.h:229:37: note: in expansion of macro 'DEVICE_NAME_GET'
      229 | #define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_ID(node_id))
          |                                     ^~~~~~~~~~~~~~~
    /Users/ianaber/Documents/Projects/Nordic/Zigbee/zephyr/include/zephyr/device.h:246:34: note: in expansion of macro 'DEVICE_DT_NAME_GET'
      246 | #define DEVICE_DT_GET(node_id) (&DEVICE_DT_NAME_GET(node_id))
          |                                  ^~~~~~~~~~~~~~~~~~
    /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/subsys/osif/zb_nrf_serial_logger.c:20:40: note: in expansion of macro 'DEVICE_DT_GET'
       20 | static const struct device *uart_dev = DEVICE_DT_GET(DT_CHOSEN(ncs_zboss_trace_uart));
          |                                        ^~~~~~~~~~~~~
    [421/432] Building C object modules/ncs-zigbee/subsys/lib/zigbee_scenes/CMakeFiles/..__ncs-zigbee__subsys__lib__zigbee_scen[422/432] Building C object modules/ncs-zigbee/subsys/lib/zigbee_app_utils/CMakeFiles/..__ncs-zigbee__subsys__lib__zigbee_app_utils.dir/zigbee_app_utils.c.obj
    ninja: build stopped: subcommand failed.
    FAILED: _sysbuild/sysbuild/images/light_bulb-prefix/src/light_bulb-stamp/light_bulb-build /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/samples/light_bulb/build/_sysbuild/sysbuild/images/light_bulb-prefix/src/light_bulb-stamp/light_bulb-build 
    cd /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/samples/light_bulb/build/light_bulb && /opt/nordic/ncs/toolchains/561dce9adf/Cellar/cmake/3.21.0/bin/cmake --build .
    ninja: build stopped: subcommand failed.
    FATAL ERROR: command exited with status 1: /opt/nordic/ncs/toolchains/561dce9adf/bin/cmake --build /Users/ianaber/Documents/Projects/Nordic/Zigbee/ncs-zigbee/samples/light_bulb/build
    

    What should I do next?

  • Sorry, I forgot one thing you need to add to your .overlay file:

    &uart1 {
    	status = "okay";
    };

    In order to enable uart1. 

    So now, you either need to add a uart connector (you can use another DK, and short the RX and TX pins of the UART 1 on your test DK to the default UART0 pins on the other DK, or you can use a standalone UART -> USB bridge, to read the uart data. Alternatively, you can try to put it on UART0, by using:

    ncs,zboss-trace-uart = &uart0;

    instead of 

    ncs,zboss-trace-uart = &uart1;

    in the overlay file. 

    Best regards,

    Edvin

  • Thanks Edvin. Since I do not have a second DK available and I do not have a ttl to uart to usb adapter either (I just ordered one but it will take a few days to come), I thought I should try UART0. I changed the line in the prj.conf file and the code is now outputting stuff on the UART debug terminal connected to the DK. The problem now is that the output is garbled...

    �g"#x��ޭ&�g"G
                  �����Y�����ޭ�g"
    ޭ�g��&�g"G
              ���}�����ޭ�g"
    ޭ�g"z�  ޭ�g"z�
    ޭ�g "zD �xޭ�g!"zlޭ�g""z{��ޭ�g#"z��u0r���g$"z��4 
    ޭ�g%"z�����s��.��(                              o
                      �ޭ�g&"z�ZigBeeAlliance09ޭ�g'"zr�#�� dޭ�g("z�ޭ�g)"zB�#ޭ�g*"z�    $$���g+"z'
    ޭ�g,"z� ޭ�g-"z�
    ޭ�g."zD �xޭ�g/"zlޭ�g0"z{��ޭ�g1"z��u0rޭ�g2"z��4 
    ���g3"z����s��.��(                             o
                      �ޭ�g4"z�ZigBeeAlliance09���g5"zr0$�� dޭ�g6"z�ޭ�g7"zB0$ޭ�g8"z�  �$ޭ�g9"z'
    ޭ�g:"
    ޭ�g;"
    ޭ�g<"#x�B��&�g="G
                     �B��n�����ޭ�g>"
    ޭh?"
    h@""ޭhA"+ޭhB".2�
    hC"RI: Unimplemented signal (signal: 52, status: 0)
    ޭhD"#x�ޭ&hE"G
                 ������ޭ hF"
    ޭPhG"#x�ޭ&PhH"G
                   ���4_�����ޭPhI"
    ޭ�hJ"#x�ޭ&�hK"G
                   ���_|����ޭ�hL"
    ޭ�hM"#x�~ޭ&�hN"G
                    �~��`}T����ޭ�hO"
    ޭ�hP"#x�Eޭ&�hQ"G
                    �E���z��������hR"

    As you can see, there are some bits where the text is readable so it does not appear to be a UART settings issue. Do you have any idea what is wrong here? What have I missed?

  • I have now received a TTL UART to USB adapter and connected it to the nRF52840DK. I connected the RX input on the adapter to P1.02 and TX output to P1.01. I used Serial Tools on the Mac to monitor the serial data and set it to 115000 baud, 8 bits no parity. I set the prj.conf and the overlay files as you suggested.

    I see output coming from the nRF52840DK, but as with the previous configuration it is unintelligible...

    Ñ,G4ÿÿ’e`ºÿÿÿÞ­>Ò,
    Þ­DÓ,#xùEÞ­&DÔ,GùEÿÿôw€ÃÿÿÿÞ­EÕ,
    Þ­iÖ,#x£…Þ­&i×,G£…ÿÿt_L¶ÿÿÿÞ­iØ,
    Þ­zÙ,#x¯Þ­&zÚ,G¯ÿÿÒ_`»ÿÿÿÞ­{Û,
    Þ­·Ü,#xVpÞ­&·Ý,GVpÿÿZexÁÿÿÿÞ­·Þ,
    Þ­Ùß,#xlÞ­&Ùà,GlÿÿJ_€ÄÿÿÿÞ­Úá,
    Þ­Ýâ,#x	 Þ­&Ýã,G	 ÿÿQbP¶ÿÿÿÞ­Ýä,
    Þ­äå,#x—Þ­&äæ,G—ÿÿ¹_P¶ÿÿÿÞ­åç,
    Þ­ýè,#xÞ­&ýé,Gÿÿù}°ÐÿÿÿÞ­ýê,
    Þ­*
    ë,#x¹èÞ­&*
    ì,G¹èÿÿÕbxÁÿÿÿÞ­+
    í,
    

  • After further reading I see that the ZBOSS trace is supposed to be in binary format. I have saved it to a file and attached it. I hope this works...ZBOS Trace.txt

    This trace was started as the network join was initiated. The nRF52840 joined the network and then I turned the light on and off a few times. I adjusted its brightness then returned to turning it on and off. After a minute or so it stopped responding to commands, after which the trace was stopped and saved.

Related