feat(zigbee): upgrade zigbee example to v2.0

This commit is contained in:
xieqinan@espressif.com
2026-09-09 11:34:28 +08:00
parent a8a5106421
commit 256403fe73
53 changed files with 1880 additions and 1251 deletions
@@ -1,4 +1,4 @@
idf_component_register(SRCS "esp_zigbee_gateway.c"
PRIV_REQUIRES ieee802154 esp_driver_usb_serial_jtag esp_coex esp_netif
vfs esp_wifi nvs_flash esp_driver_uart
INCLUDE_DIRS ".")
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES ieee802154 esp_driver_usb_serial_jtag esp_coex esp_netif
vfs esp_wifi spiffs nvs_flash esp_driver_uart)
@@ -0,0 +1,17 @@
choice ZB_GW_RCP_CHIP
depends on AUTO_UPDATE_RCP
prompt "Zigbee gateway RCP chip for auto update"
default ZB_GW_RCP_CHIP_ESP32H2
help
Select the RCP chip connected to the Zigbee gateway.
config ZB_GW_RCP_CHIP_ESP32H2
bool "ESP32-H2"
help
ESP32-H2 is the RCP chip connected to the Zigbee gateway.
config ZB_GW_RCP_CHIP_ESP32C6
bool "ESP32-C6"
help
ESP32-C6 is the RCP chip connected to the Zigbee gateway.
endchoice
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
@@ -11,172 +11,255 @@
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <fcntl.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/usb_serial_jtag.h"
#include "esp_coexist.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_vfs_dev.h"
#include "esp_vfs_eventfd.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#if CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "esp_zigbee_gateway.h"
#include "zb_config_platform.h"
static const char *TAG = "ESP_ZB_GATEWAY";
/* Note: Please select the correct console output port based on the development board in menuconfig */
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
esp_err_t esp_zb_gateway_console_init(void)
{
esp_err_t ret = ESP_OK;
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
usb_serial_jtag_vfs_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Enable non-blocking mode on stdin and stdout */
fcntl(fileno(stdout), F_SETFL, O_NONBLOCK);
fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
usb_serial_jtag_vfs_use_driver();
uart_vfs_dev_register();
return ret;
}
#if CONFIG_EXAMPLE_CONNECT_WIFI
#include "esp_wifi.h"
#endif
#endif
static void bdb_start_top_level_commissioning_cb(uint8_t mode_mask)
#if CONFIG_AUTO_UPDATE_RCP
#include "zigbee_rcp.h"
#endif
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE
#include "esp_coexist.h"
#endif
#include "light_driver.h"
#include "alarm_timer.h"
#include "esp_zigbee.h"
#include "ezbee/zha.h"
#include "esp_zigbee_gateway.h"
static const char *TAG = "ZIGBEE_GATEWAY";
#if (CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET)
static esp_err_t esp_zigbee_connect_netif(void)
{
ESP_RETURN_ON_FALSE(esp_zb_bdb_start_top_level_commissioning(mode_mask) == ESP_OK, , TAG, "Failed to start Zigbee bdb commissioning");
esp_err_t ret = ESP_OK;
#if CONFIG_EXAMPLE_CONNECT_WIFI
wifi_ps_type_t ps_type = WIFI_PS_NONE;
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE
ps_type = WIFI_PS_MIN_MODEM;
#endif /* CONFIG_ESP_COEX_SW_COEXIST_ENABLE */
#endif /* CONFIG_EXAMPLE_CONNECT_WIFI */
ESP_RETURN_ON_ERROR(esp_netif_init(), TAG, "Failed to initialize network interface");
ESP_RETURN_ON_ERROR(esp_event_loop_create_default(), TAG, "Failed to create event loop");
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE
esp_coex_wifi_i154_enable();
#endif /* CONFIG_ESP_COEX_SW_COEXIST_ENABLE*/
ESP_RETURN_ON_ERROR(example_connect(), TAG, "Failed to connect to Network Interface");
#if CONFIG_EXAMPLE_CONNECT_WIFI
ESP_RETURN_ON_ERROR(esp_wifi_set_ps(ps_type), TAG, "Failed to set power save type for Wi-Fi");
#endif /* CONFIG_EXAMPLE_CONNECT_WIFI */
return ret;
}
#endif /* (CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET) */
static esp_err_t deferred_driver_init(void)
{
static bool is_inited = false;
ESP_RETURN_ON_FALSE(!is_inited, ESP_OK, TAG, "Deferred driver already initialized");
light_driver_init(false);
is_inited = true;
return ESP_OK;
}
void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct)
static void esp_zigbee_alarm_bdb_commissioning(alarm_timer_arg_t arg)
{
uint32_t *p_sg_p = signal_struct->p_app_signal;
esp_err_t err_status = signal_struct->esp_err_status;
esp_zb_app_signal_type_t sig_type = *p_sg_p;
esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL;
esp_zigbee_lock_acquire(portMAX_DELAY);
(void)ezb_bdb_start_top_level_commissioning(arg);
esp_zigbee_lock_release();
}
switch (sig_type) {
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP:
#if CONFIG_EXAMPLE_CONNECT_WIFI
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE
esp_coex_wifi_i154_enable();
#endif /* CONFIG_ESP_COEX_SW_COEXIST_ENABLE */
ESP_RETURN_ON_FALSE(example_connect() == ESP_OK, , TAG, "Failed to connect to Wi-Fi");
ESP_RETURN_ON_FALSE(esp_wifi_set_ps(WIFI_PS_MIN_MODEM) == ESP_OK, , TAG, "Failed to set Wi-Fi minimum modem power save type");
#endif /* CONFIG_EXAMPLE_CONNECT_WIFI */
static bool esp_zigbee_app_signal_handler(const ezb_app_signal_t *app_signal)
{
ezb_app_signal_type_t signal_type = ezb_app_signal_get_type(app_signal);
switch (signal_type) {
case EZB_ZDO_SIGNAL_SKIP_STARTUP:
ESP_LOGI(TAG, "Initialize Zigbee stack");
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION);
ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_INITIALIZATION);
break;
case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START:
case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT:
if (err_status == ESP_OK) {
ESP_LOGI(TAG, "Device started up in %s factory-reset mode", esp_zb_bdb_is_factory_new() ? "" : "non");
if (esp_zb_bdb_is_factory_new()) {
ESP_LOGI(TAG, "Start network formation");
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION);
case EZB_BDB_SIGNAL_DEVICE_FIRST_START:
case EZB_BDB_SIGNAL_DEVICE_REBOOT: {
ezb_bdb_comm_status_t status = *((ezb_bdb_comm_status_t *)ezb_app_signal_get_params(app_signal));
if (status == EZB_BDB_STATUS_SUCCESS) {
ESP_LOGI(TAG, "Deferred driver initialization %s", deferred_driver_init() ? "failed" : "successful");
ESP_LOGI(TAG, "Device started up in%s factory-reset mode", ezb_bdb_is_factory_new() ? "" : " non");
if (ezb_bdb_is_factory_new()) {
ESP_ERROR_CHECK(ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_NETWORK_FORMATION));
} else {
esp_zb_bdb_open_network(180);
ESP_LOGI(TAG, "Device rebooted");
ezb_bdb_open_network(180);
ESP_LOGI(TAG, "Device reboot");
}
} else {
ESP_LOGE(TAG, "Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status));
ESP_LOGW(TAG, "The %s failed with status(0x%02x), please retry", ezb_app_signal_to_string(signal_type), status);
alarm_timer_schedule(esp_zigbee_alarm_bdb_commissioning, EZB_BDB_MODE_INITIALIZATION, 1000);
}
break;
case ESP_ZB_BDB_SIGNAL_FORMATION:
if (err_status == ESP_OK) {
esp_zb_ieee_addr_t ieee_address;
esp_zb_get_long_address(ieee_address);
ESP_LOGI(TAG, "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)",
ieee_address[7], ieee_address[6], ieee_address[5], ieee_address[4],
ieee_address[3], ieee_address[2], ieee_address[1], ieee_address[0],
esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address());
esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING);
} break;
case EZB_BDB_SIGNAL_FORMATION: {
ezb_bdb_comm_status_t status = *((ezb_bdb_comm_status_t *)ezb_app_signal_get_params(app_signal));
if (status == EZB_BDB_STATUS_SUCCESS) {
ezb_extpanid_t extended_pan_id;
ezb_nwk_get_extended_panid(&extended_pan_id);
ESP_LOGI(TAG, "Formed network successfully: PAN ID(0x%04hx, EXT: 0x%llx), Channel(%d), Short Address(0x%04hx)",
ezb_nwk_get_panid(), extended_pan_id.u64, ezb_nwk_get_current_channel(), ezb_nwk_get_short_address());
ezb_bdb_start_top_level_commissioning(EZB_BDB_MODE_NETWORK_STEERING);
} else {
ESP_LOGI(TAG, "Restart network formation (status: %s)", esp_err_to_name(err_status));
esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_FORMATION, 1000);
ESP_LOGW(TAG, "Failed to form network with status(0x%02x)", status);
alarm_timer_schedule(esp_zigbee_alarm_bdb_commissioning, EZB_BDB_MODE_NETWORK_FORMATION, 1000);
}
break;
case ESP_ZB_BDB_SIGNAL_STEERING:
if (err_status == ESP_OK) {
ESP_LOGI(TAG, "Network steering started");
} break;
case EZB_BDB_SIGNAL_STEERING: {
ezb_bdb_comm_status_t status = *((ezb_bdb_comm_status_t *)ezb_app_signal_get_params(app_signal));
if (status == EZB_BDB_STATUS_SUCCESS) {
ESP_LOGI(TAG, "Network steering completed");
} else {
ESP_LOGW(TAG, "Failed to steering network with status(0x%02x)", status);
alarm_timer_schedule(esp_zigbee_alarm_bdb_commissioning, EZB_BDB_MODE_NETWORK_FORMATION, 1000);
}
break;
case ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE:
dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t *)esp_zb_app_signal_get_params(p_sg_p);
ESP_LOGI(TAG, "New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr);
break;
case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS:
if (err_status == ESP_OK) {
if (*(uint8_t *)esp_zb_app_signal_get_params(p_sg_p)) {
ESP_LOGI(TAG, "Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), *(uint8_t *)esp_zb_app_signal_get_params(p_sg_p));
} else {
ESP_LOGW(TAG, "Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id());
}
} break;
case EZB_ZDO_SIGNAL_DEVICE_ANNCE: {
const ezb_zdo_signal_device_annce_params_t *dev_annce_params = ezb_app_signal_get_params(app_signal);
ESP_LOGI(TAG, "New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->short_addr);
} break;
case EZB_ZDO_SIGNAL_LEAVE_INDICATION: {
const ezb_zdo_signal_leave_indication_params_t *leave_ind_params = ezb_app_signal_get_params(app_signal);
ESP_LOGI(TAG, "Zigbee Node(0x%04hx) is leaving network", leave_ind_params->short_addr);
} break;
case EZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: {
uint8_t duration = *(uint8_t *)ezb_app_signal_get_params(app_signal);
if (duration) {
ESP_LOGI(TAG, "Network(0x%04hx) is open for %d seconds", ezb_nwk_get_panid(), duration);
} else {
ESP_LOGW(TAG, "Network(0x%04hx) closed, devices joining not allowed.", ezb_nwk_get_panid());
}
break;
case ESP_ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
ESP_LOGI(TAG, "Production configuration is %s", err_status == ESP_OK ? "ready" : "not present");
esp_zb_set_node_descriptor_manufacturer_code(ESP_MANUFACTURER_CODE);
break;
} break;
default:
ESP_LOGI(TAG, "ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type,
esp_err_to_name(err_status));
ESP_LOGI(TAG, "Zigbee APP Signal: %s(type: 0x%02x)", ezb_app_signal_to_string(signal_type), signal_type);
break;
}
return true;
}
static void zcl_core_set_attr_value_handler(ezb_zcl_set_attr_value_message_t *message)
{
ESP_RETURN_ON_FALSE(message, , TAG, "message is empty");
ESP_LOGI(TAG, "ZCL SetAttributeValue message for endpoint(%d) cluster(0x%04x) %s with status(0x%02x)", message->info.dst_ep,
message->info.cluster_id, message->info.cluster_role == EZB_ZCL_CLUSTER_SERVER ? "server" : "client",
message->info.status);
if (message->info.cluster_id == EZB_ZCL_CLUSTER_ID_ON_OFF) {
light_driver_set_power(*(uint8_t *)message->in.attribute.data.value);
ESP_LOGI(TAG, "Set On/Off: %d", *(uint8_t *)message->in.attribute.data.value);
} else {
ESP_LOGW(TAG, "Unsupported cluster ID(0x%04x)", message->info.cluster_id);
}
}
static void esp_zigbee_zcl_core_action_handler(ezb_zcl_core_action_callback_id_t callback_id, void *message)
{
switch (callback_id) {
case EZB_ZCL_CORE_SET_ATTR_VALUE_CB_ID:
zcl_core_set_attr_value_handler(message);
break;
case EZB_ZCL_CORE_DEFAULT_RSP_CB_ID: {
ezb_zcl_cmd_default_rsp_message_t *default_rsp = (ezb_zcl_cmd_default_rsp_message_t *)message;
ESP_LOGI(TAG, "Received ZCL Default Response with status(0x%02x)", default_rsp->in.status_code);
} break;
default:
ESP_LOGW(TAG, "ZCL Core Action: ID(0x%04lx)", callback_id);
break;
}
}
static void esp_zb_task(void *pvParameters)
esp_err_t esp_zigbee_create_zha_gateway_device(void)
{
/* initialize Zigbee stack */
esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZC_CONFIG();
esp_zb_init(&zb_nwk_cfg);
esp_zb_set_primary_network_channel_set(ESP_ZB_PRIMARY_CHANNEL_MASK);
esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();
esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
esp_zb_endpoint_config_t endpoint_config = {
.endpoint = ESP_ZB_GATEWAY_ENDPOINT,
.app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
.app_device_id = ESP_ZB_HA_REMOTE_CONTROL_DEVICE_ID,
.app_device_version = 0,
};
ezb_af_device_desc_t dev_desc = ezb_af_create_device_desc();
ezb_zha_custom_gateway_config_t gateway_cfg = EZB_ZHA_CUSTOM_GATEWAY_CONFIG();
ezb_af_ep_desc_t ep_desc = ezb_zha_create_custom_gateway(ESP_ZIGBEE_CUSTOM_GATEWAY_EP_ID, &gateway_cfg);
ezb_zcl_cluster_desc_t basic_desc = {0};
basic_desc = ezb_af_endpoint_get_cluster_desc(ep_desc, EZB_ZCL_CLUSTER_ID_BASIC, EZB_ZCL_CLUSTER_SERVER);
ezb_zcl_basic_cluster_desc_add_attr(basic_desc, EZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)ESP_MANUFACTURER_NAME);
ezb_zcl_basic_cluster_desc_add_attr(basic_desc, EZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)ESP_MODEL_IDENTIFIER);
ezb_af_endpoint_add_cluster_desc(ep_desc, ezb_zcl_on_off_create_cluster_desc(NULL, EZB_ZCL_CLUSTER_SERVER));
ESP_ERROR_CHECK(ezb_af_device_add_endpoint_desc(dev_desc, ep_desc));
ESP_ERROR_CHECK(ezb_af_device_desc_register(dev_desc));
ezb_zcl_core_action_handler_register(esp_zigbee_zcl_core_action_handler);
return ESP_OK;
}
esp_err_t esp_zigbee_setup_commissioning(void)
{
ezb_aps_secur_enable_distributed_security(false);
ESP_ERROR_CHECK(ezb_bdb_set_primary_channel_set(ESP_ZIGBEE_PRIMARY_CHANNEL_MASK));
ESP_ERROR_CHECK(ezb_bdb_set_secondary_channel_set(ESP_ZIGBEE_SECONDARY_CHANNEL_MASK));
ESP_ERROR_CHECK(ezb_app_signal_add_handler(esp_zigbee_app_signal_handler));
return ESP_OK;
}
static void esp_zigbee_stack_main_task(void *pvParameters)
{
esp_zigbee_config_t zigbee_config = ESP_ZIGBEE_DEFAULT_CONFIG();
#if CONFIG_AUTO_UPDATE_RCP
esp_rcp_update_config_t rcp_config = ESP_ZIGBEE_RCP_CONFIG();
ESP_ERROR_CHECK(esp_zigbee_rcp_init(&rcp_config));
#endif
ESP_ERROR_CHECK(esp_zigbee_init(&zigbee_config));
#if CONFIG_AUTO_UPDATE_RCP
ESP_ERROR_CHECK(esp_zigbee_rcp_update());
#endif
#if (CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET)
ESP_ERROR_CHECK(esp_zigbee_connect_netif());
#endif
ESP_ERROR_CHECK(esp_zigbee_setup_commissioning());
ESP_ERROR_CHECK(esp_zigbee_create_zha_gateway_device());
ESP_ERROR_CHECK(esp_zigbee_start(false));
esp_zigbee_launch_mainloop();
esp_zigbee_deinit();
#if CONFIG_AUTO_UPDATE_RCP
esp_zigbee_rcp_deinit();
#endif
esp_zb_attribute_list_t *basic_cluser = esp_zb_basic_cluster_create(NULL);
esp_zb_basic_cluster_add_attr(basic_cluser, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, ESP_MANUFACTURER_NAME);
esp_zb_basic_cluster_add_attr(basic_cluser, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, ESP_MODEL_IDENTIFIER);
esp_zb_cluster_list_add_basic_cluster(cluster_list, basic_cluser, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_ep_list_add_gateway_ep(ep_list, cluster_list, endpoint_config);
esp_zb_device_register(ep_list);
ESP_ERROR_CHECK(esp_zb_start(false));
esp_zb_stack_main_loop();
vTaskDelete(NULL);
}
void app_main(void)
{
esp_zb_platform_config_t config = {
.radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_ZB_DEFAULT_HOST_CONFIG(),
};
ESP_ERROR_CHECK(esp_zb_platform_config(&config));
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
ESP_ERROR_CHECK(esp_zb_gateway_console_init());
#endif
xTaskCreate(esp_zb_task, "Zigbee_main", 8192, NULL, 5, NULL);
ESP_LOGI(TAG, "Start ESP Zigbee Stack");
xTaskCreate(esp_zigbee_stack_main_task, "Zigbee_main", 4096 * 2, NULL, 5, NULL);
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
@@ -12,62 +12,87 @@
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include "esp_err.h"
#include "esp_zigbee_core.h"
#pragma once
/* Zigbee Configuration */
#define MAX_CHILDREN 10 /* the max amount of connected devices */
#define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */
#define ESP_ZB_PRIMARY_CHANNEL_MASK (1l << 13) /* Zigbee primary channel mask use in the example */
#define ESP_ZB_GATEWAY_ENDPOINT 1 /* Gateway endpoint identifier */
#define APP_PROD_CFG_CURRENT_VERSION 0x0001 /* Production configuration version */
#define ESP_ZIGBEE_PRIMARY_CHANNEL_MASK (1U << CONFIG_ZB_EXAMPLE_PRIMARY_CHANNEL)
#define ESP_ZIGBEE_SECONDARY_CHANNEL_MASK CONFIG_ZB_EXAMPLE_SECONDARY_CHANNEL_MASK
/* Basic manufacturer information */
#define ESP_MANUFACTURER_CODE 0x131B /* Customized manufacturer code */
#define ESP_MANUFACTURER_NAME "\x09""ESPRESSIF" /* Customized manufacturer name */
#define ESP_MODEL_IDENTIFIER "\x07"CONFIG_IDF_TARGET /* Customized model identifier */
#define ESP_ZIGBEE_CUSTOM_GATEWAY_EP_ID (10)
/* RCP connection pins */
#define HOST_RX_PIN_TO_RCP_TX 4
#define HOST_TX_PIN_TO_RCP_RX 5
#define ESP_ZIGBEE_STORAGE_PARTITION_NAME "nvs"
#define ESP_ZB_ZC_CONFIG() \
{ \
.esp_zb_role = ESP_ZB_DEVICE_TYPE_COORDINATOR, \
.install_code_policy = INSTALLCODE_POLICY_ENABLE, \
.nwk_cfg.zczr_cfg = { \
.max_children = MAX_CHILDREN, \
}, \
#define ESP_MANUFACTURER_NAME "\x09""ESPRESSIF"
#define ESP_MODEL_IDENTIFIER "\x07"CONFIG_IDF_TARGET
#if defined(CONFIG_ZB_GW_RCP_CHIP_ESP32C6)
#define ESP_ZIGBEE_RCP_TARGET_CHIP ESP32C6_CHIP
#elif defined(CONFIG_ZB_GW_RCP_CHIP_ESP32H2)
#define ESP_ZIGBEE_RCP_TARGET_CHIP ESP32H2_CHIP
#else
#define ESP_ZIGBEE_RCP_TARGET_CHIP ESP_UNKNOWN_CHIP
#endif
#define ESP_ZIGBEE_ZC_CONFIG() \
{ \
.device_type = EZB_NWK_DEVICE_TYPE_COORDINATOR, \
.install_code_policy = false, \
.zczr_config = { \
.max_children = 10, \
}, \
}
#if CONFIG_ZB_RADIO_NATIVE
#define ESP_ZB_DEFAULT_RADIO_CONFIG() \
{ \
.radio_mode = ZB_RADIO_MODE_NATIVE, \
#if CONFIG_SOC_IEEE802154_SUPPORTED
#define ESP_ZIGBEE_PLATFORM_CONFIG() \
{ \
.storage_partition_name = ESP_ZIGBEE_STORAGE_PARTITION_NAME, \
.radio_config = { \
.radio_mode = ESP_ZIGBEE_RADIO_MODE_NATIVE, \
}, \
}
#else
#define ESP_ZB_DEFAULT_RADIO_CONFIG() \
{ \
.radio_mode = ZB_RADIO_MODE_UART_RCP, \
.radio_uart_config = { \
.port = 1, \
.uart_config = \
{ \
.baud_rate = 460800, \
.data_bits = UART_DATA_8_BITS, \
.parity = UART_PARITY_DISABLE, \
.stop_bits = UART_STOP_BITS_1, \
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
.rx_flow_ctrl_thresh = 0, \
.source_clk = UART_SCLK_DEFAULT, \
}, \
.rx_pin = HOST_RX_PIN_TO_RCP_TX, \
.tx_pin = HOST_TX_PIN_TO_RCP_RX, \
}, \
#define ESP_ZIGBEE_UART_CONFIG() \
{ \
.port = 1, \
.uart_config = \
{ \
.baud_rate = 460800, \
.data_bits = UART_DATA_8_BITS, \
.parity = UART_PARITY_DISABLE, \
.stop_bits = UART_STOP_BITS_1, \
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
.rx_flow_ctrl_thresh = 0, \
.source_clk = UART_SCLK_DEFAULT, \
}, \
.rx_pin = CONFIG_DEFAULT_PIN_TO_RCP_TX, \
.tx_pin = CONFIG_DEFAULT_PIN_TO_RCP_RX, \
}
#define ESP_ZIGBEE_PLATFORM_CONFIG() \
{ \
.storage_partition_name = ESP_ZIGBEE_STORAGE_PARTITION_NAME, \
.radio_config = { \
.radio_mode = ESP_ZIGBEE_RADIO_MODE_UART_RCP, \
.radio_uart_config = ESP_ZIGBEE_UART_CONFIG(), \
}, \
}
#endif
#define ESP_ZB_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE, \
}
#define ESP_ZIGBEE_DEFAULT_CONFIG() \
{ \
.device_config = ESP_ZIGBEE_ZC_CONFIG(), \
.platform_config = ESP_ZIGBEE_PLATFORM_CONFIG(), \
};
#define ESP_ZIGBEE_RCP_CONFIG() \
{ \
.rcp_type = RCP_TYPE_UART, \
.uart_rx_pin = CONFIG_DEFAULT_PIN_TO_RCP_TX, \
.uart_tx_pin = CONFIG_DEFAULT_PIN_TO_RCP_RX, \
.uart_port = 1, \
.uart_baudrate = 115200, \
.reset_pin = CONFIG_DEFAULT_PIN_TO_RCP_RESET, \
.boot_pin = CONFIG_DEFAULT_PIN_TO_RCP_BOOT, \
.update_baudrate = 460800, \
.firmware_dir = "/" CONFIG_RCP_PARTITION_NAME "/ot_rcp", \
.target_chip = ESP_ZIGBEE_RCP_TARGET_CHIP, \
}
@@ -1,9 +1,13 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp-zboss-lib: "~1.6.0"
espressif/esp-zigbee-lib: "~1.6.0"
## Required IDF version
espressif/esp_rcp_update: "~1.6.0"
espressif/esp-zigbee-lib:
version: ">=2.0.0"
idf:
version: ">=5.0.0"
version: ">=5.2"
example_common:
path: ${IDF_PATH}/examples/zigbee/zb_common_components/example_common
light_driver:
path: ${IDF_PATH}/examples/zigbee/zb_common_components/light_driver
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
@@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "esp_log.h"
#include "esp_check.h"
#include "sdkconfig.h"
#if CONFIG_AUTO_UPDATE_RCP
#include "esp_rcp_update.h"
#include "esp_spiffs.h"
#endif
#if CONFIG_OPENTHREAD_SPINEL_ONLY
#include "esp_radio_spinel.h"
#define ESP_ZIGBEE_RCP_VERSION_MAX_SIZE 80
#endif
#include "esp_zigbee.h"
#include "zigbee_rcp.h"
#define TAG "ZIGBEE_RCP"
#if CONFIG_AUTO_UPDATE_RCP
static void rcp_update(void)
{
ESP_LOGI(TAG, "Update RCP");
/* Stop Zigbee stack during RCP update */
esp_zigbee_deinit();
if (esp_rcp_update() != ESP_OK) {
esp_rcp_mark_image_verified(false);
}
esp_restart();
}
static void rcp_fatal_failure_handler(void)
{
#if CONFIG_AUTO_UPDATE_RCP
ESP_LOGW(TAG, "RCP failure, re-flashing RCP");
rcp_update();
#endif
esp_restart();
}
static void rcp_failure_handler(void)
{
ESP_LOGW(TAG, "RCP failure, reset RCP");
esp_rcp_reset();
}
esp_err_t esp_zigbee_rcp_update(void)
{
char rcp_version[ESP_ZIGBEE_RCP_VERSION_MAX_SIZE] = {0};
ESP_RETURN_ON_ERROR(esp_radio_spinel_rcp_version_get(rcp_version, ESP_RADIO_SPINEL_ZIGBEE), TAG,
"Failed to get rcp version from radio spinel");
#if (CONFIG_AUTO_UPDATE_RCP)
char storage_rcp_version[ESP_ZIGBEE_RCP_VERSION_MAX_SIZE] = {0};
if (esp_rcp_load_version_in_storage(storage_rcp_version, sizeof(storage_rcp_version)) == ESP_OK) {
if (strcmp(storage_rcp_version, rcp_version)) {
ESP_LOGI(TAG, "Update the RCP version from %s to %s", storage_rcp_version, rcp_version);
rcp_update();
} else {
ESP_LOGI(TAG, "Running RCP version: %s", rcp_version);
esp_rcp_mark_image_verified(true);
}
} else {
ESP_LOGI(TAG, "No RCP firmware found in storage, reboot to try next image");
esp_rcp_mark_image_verified(false);
esp_restart();
}
#endif
return ESP_OK;
}
static esp_err_t spiffs_init(void)
{
esp_vfs_spiffs_conf_t rcp_fw_conf = {
.base_path = "/" CONFIG_RCP_PARTITION_NAME,
.partition_label = CONFIG_RCP_PARTITION_NAME,
.max_files = 10,
.format_if_mount_failed = false,
};
return esp_vfs_spiffs_register(&rcp_fw_conf);
}
static void spiffs_deinit(void)
{
esp_vfs_spiffs_unregister(CONFIG_RCP_PARTITION_NAME);
}
esp_err_t esp_zigbee_rcp_init(esp_rcp_update_config_t *config)
{
ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TAG, "config is NULL");
ESP_ERROR_CHECK(spiffs_init());
ESP_ERROR_CHECK(esp_rcp_update_init(config));
#if CONFIG_OPENTHREAD_SPINEL_ONLY
esp_radio_spinel_register_rcp_failure_handler(rcp_failure_handler, ESP_RADIO_SPINEL_ZIGBEE);
esp_radio_spinel_set_compatibility_error_callback(rcp_fatal_failure_handler);
esp_radio_spinel_set_coprocessor_reset_failure_callback(rcp_fatal_failure_handler);
#endif
return ESP_OK;
}
void esp_zigbee_rcp_deinit(void)
{
#if CONFIG_OPENTHREAD_SPINEL_ONLY
esp_radio_spinel_set_coprocessor_reset_failure_callback(NULL);
esp_radio_spinel_set_compatibility_error_callback(NULL);
esp_radio_spinel_register_rcp_failure_handler(NULL, ESP_RADIO_SPINEL_ZIGBEE);
#endif
esp_rcp_update_deinit();
spiffs_deinit();
}
#endif
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "esp_err.h"
#include "esp_rcp_update.h"
esp_err_t esp_zigbee_rcp_init(esp_rcp_update_config_t *config);
void esp_zigbee_rcp_deinit(void);
esp_err_t esp_zigbee_rcp_update(void);