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
+126 -96
View File
@@ -1,46 +1,68 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | --------- |
# Gateway Example
This example demonstrates how to build a Zigbee Gateway device.
This example demonstrates how to build a Zigbee Gateway device. It runs on a Wi-Fi SoC such as ESP32, ESP32-C3 and ESP32-S3, with an 802.15.4 SoC like ESP32-H2
running [ot_rcp](https://github.com/espressif/esp-idf/tree/master/examples/openthread/ot_rcp) to provide 802.15.4 radio.
The ESP Zigbee SDK provides more examples and tools for productization:
* [ESP Zigbee SDK Docs](https://docs.espressif.com/projects/esp-zigbee-sdk)
* [ESP Zigbee SDK Repo](https://github.com/espressif/esp-zigbee-sdk)
## Hardware Platforms
## Hardware Required
### Wi-Fi based ESP Zigbee Gateway
By default, two SoCs are required to run this example:
* An ESP32 series Wi-Fi SoC (ESP32, ESP32-C, ESP32-S, etc) loaded with this esp_zigbee_gateway example.
* An ESP32-H2 802.15.4 SoC loaded with [ot_rcp](../../openthread/ot_rcp/) example
The Wi-Fi based ESP Zigbee Gateway consists of two SoCs:
Connect the two SoCs via UART, below is an example setup with ESP32-DevKitC and ESP32-H2-DevKitC:
![Zigbee_gateway](../../openthread/ot_br/image/thread-border-router-esp32-esp32h2.jpg)
* An ESP32 series Wi-Fi SoC (ESP32, ESP32-C, ESP32-S, etc) loaded with this example.
* An 802.15.4 enabled SoC (e.g., ESP32-H2 or ESP32-C6) loaded with [OpenThread RCP](https://github.com/espressif/esp-idf/tree/master/examples/openthread/ot_rcp) example.
#### ESP Zigbee Gateway Board
The ESP Zigbee gateway board provides an integrated module of an ESP32-S3 SoC and an ESP32-H2 RCP.
![br_dev_kit](images/esp-zigbee-gateway-board.webp)
The two SoCs are connected with following interfaces:
* UART for serial communication
* RESET and BOOT pins for RCP Update
* 3-Wires PTA for RF coexistence
No jumper wires needed. No `idf.py menuconfig` under menu "OpenThread RCP Update" configure to change.
#### Standalone Modules
The SDK also supports manually connecting an ESP32-H2 RCP to an ESP32 series Wi-Fi SoC. As one way of connection is following:
ESP32 pin | ESP32-H2 pin
------------- |-------------
GND | G
GPIO4 (RX) | TX
GPIO5 (TX) | RX
GPI017 | RST
GPIO18 | GPIO9(BOOT)
* TX, RX pin can be also configured by user in esp_zigbee_gateway.h
TX, RX, RST and BOOT pin from ESP32 side can be configured by user in `idf.py menuconfig` under menu "ESP Zigbee gateway rcp update".
The example could also run on a single SoC which supports both Wi-Fi and Zigbee (e.g., ESP32-C6), but since there is only one RF path in ESP32-C6, which means Wi-Fi and Zigbee can't receive simultaneously, it has a significant impact on performance. Hence the two SoCs solution is recommended.
TX, RX pins from ESP32-H2 should be configured in [ot_rcp example](https://github.com/espressif/esp-idf/tree/master/examples/openthread/ot_rcp) via "OpenThread RCP Example > Configure RCP UART pin manually" options.
## Configure the RCP
Other pin number is also available for user to configure if needed.
The `OPENTHREAD_NCP_VENDOR_HOOK` of `ot_rcp` should be selected via menuconfig when the [ot_rcp](../../openthread/ot_rcp/) example is built. Then use `idf.py -p PORT erase-flash` to flash the RCP firmware to ESP32-H2-DevKitC.
The following image shows an example connection between ESP32 DevKitC and ESP32-H2 DevKitC:
## Configure the project
![Zigbee_gateway](images/esp-zigbee-standalone-modules.webp)
Before project configuration and build, make sure to set the correct chip target using `idf.py set-target <chip_name>`.
## Erase the NVRAM
In order to run the example on single SoC which supports both Wi-Fi and Thread, the option `CONFIG_ESP_COEX_SW_COEXIST_ENABLE` and option `CONFIG_ZB_RADIO_NATIVE` should be enabled. The two options are enabled by default for ESP32-C6 target.
Before flash it to the board, it is recommended to erase NVRAM if user doesn't want to keep the previous examples or other projects stored info
using `idf.py -p PORT erase-flash`
## Erase the NVRAM
## Create the RCP firmware image
Before flash it to the board, it is recommended to erase NVRAM if user doesn't want to keep the previous examples or other projects stored info using `idf.py -p PORT erase-flash`
The esp_zigbee_gateway supports updating the RCP image. Generate rcp image before building the esp_zigbee_gateway example.
Build the [ot_rcp](https://github.com/espressif/esp-idf/tree/master/examples/openthread/ot_rcp) example. Later in the esp_zigbee_gateway building process, the built RCP image will be automatically packed into the esp_zigbee_gateway firmware. See detail in [CMakeLists.txt](main/CMakeLists.txt).
Notes:
- `OPENTHREAD_NCP_VENDOR_HOOK` of `ot_rcp` should be selected via menuconfig.
## Build and Flash
@@ -48,86 +70,94 @@ Build the project, flash it to the board, and start the monitor tool to view the
(To exit the serial monitor, type ``Ctrl-]``.)
## Example Output
## Application Functions
As you run the example, you will see the following log:
esp_zigbee_gateway:
- When the program starts, the board will attempt to read the RCP version from the remote radio via UART.
```
I (499) main_task: Calling app_main()
I (519) ESP_RADIO_SPINEL: spinel UART interface initialization completed
I (519) ESP_RADIO_SPINEL: Spinel UART interface has been successfully enabled
I (519) ZB_ESP_SPINEL: Spinel UART interface enable successfully
I (529) main_task: Returned from app_main()
I(529) OPENTHREAD:[I] P-RadioSpinel-: RCP reset: RESET_POWER_ON
I(539) OPENTHREAD:[I] P-RadioSpinel-: Software reset RCP successfully
I (569) ZB_ESP_SPINEL: Radio spinel workflow register successfully
I (769) ESP_ZB_GATEWAY: Production configuration is ready
W (769) ESP_ZB_GATEWAY: Production configuration is not present
I (769) example_connect: Start example_connect.
I (779) pp: pp rom version: e7ae62f
I (779) net80211: net80211 rom version: e7ae62f
I (799) wifi:wifi driver task: 3fca80d8, prio:23, stack:6656, core=0
I (799) wifi:wifi firmware version: 3ce09e5
I (799) wifi:wifi certification version: v7.0
I (799) wifi:config NVS flash: enabled
I (799) wifi:config nano formatting: disabled
I (809) wifi:Init data frame dynamic rx buffer num: 32
I (809) wifi:Init static rx mgmt buffer num: 5
I (819) wifi:Init management short buffer num: 32
I (819) wifi:Init dynamic tx buffer num: 32
I (819) wifi:Init static tx FG buffer num: 2
I (829) wifi:Init static rx buffer size: 1600
I (829) wifi:Init static rx buffer num: 10
I (839) wifi:Init dynamic rx buffer num: 32
I (839) wifi_init: rx ba win: 6
I (839) wifi_init: tcpip mbox: 32
I (849) wifi_init: udp mbox: 6
I (849) wifi_init: tcp mbox: 6
I (849) wifi_init: tcp tx win: 5760
I (859) wifi_init: tcp rx win: 5760
I (859) wifi_init: tcp mss: 1440
I (869) wifi_init: WiFi IRAM OP enabled
I (869) wifi_init: WiFi RX IRAM OP enabled
I (879) phy_init: phy_version 670,b7bc9b9,Apr 30 2024,10:54:13
W (879) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
I (989) wifi:mode : sta (f4:12:fa:41:a7:f4)
I (989) wifi:enable tsf
I (999) example_connect: Connecting to esp-office-2.4G...
I (999) example_connect: Waiting for IP(s)
I (3409) wifi:new:<13,0>, old:<1,0>, ap:<255,255>, sta:<13,0>, prof:1
I (3649) wifi:state: init -> auth (b0)
I (3719) wifi:state: auth -> assoc (0)
I (3759) wifi:state: assoc -> run (10)
I (3769) wifi:connected with esp-office-2.4G, aid = 1, channel 13, BW20, bssid = 9c:3a:9a:04:18:92
I (3769) wifi:security: WPA2-PSK, phy: bgn, rssi: -42
I (3769) wifi:pm start, type: 1
I (3779) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3789) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3819) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (3849) wifi:<ba-add>idx:0 (ifx:0, 9c:3a:9a:04:18:92), tid:0, ssn:0, winSize:64
I (4799) esp_netif_handlers: example_netif_sta ip: 192.168.200.133, mask: 255.255.252.0, gw: 192.168.200.1
I (4799) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.200.133
I (5509) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:f612:faff:fe41:a7f4, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5509) example_common: Connected to example_netif_sta
I (5519) example_common: - IPv4 address: 192.168.200.133,
I (5519) example_common: - IPv6 address: fe80:0000:0000:0000:f612:faff:fe41:a7f4, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5529) wifi:Set ps type: 0, coexist: 0
I (5539) ESP_ZB_GATEWAY: Initialize Zigbee stack
I (5549) ESP_ZB_GATEWAY: Device started up in factory-reset mode
I (5549) ESP_ZB_GATEWAY: Start network formation
W (5729) ESP_ZB_GATEWAY: Network(0xb8e9) closed, devices joining not allowed.
I (5729) ESP_ZB_GATEWAY: Formed network successfully (Extended PAN ID: 60:55:f9:ff:fe:f7:73:e8, PAN ID: 0xb8e9, Channel:13, Short Address: 0x0000)
I (6339) ESP_ZB_GATEWAY: Network(0xb8e9) is open for 180 seconds
I (6339) ESP_ZB_GATEWAY: Network steering started
I (433) main_task: Started on CPU0
I (443) main_task: Calling app_main()
I (453) ZIGBEE_GATEWAY: Start ESP Zigbee Stack
I (493) main_task: Returned from app_main()
I (503) RCP_UPDATE: RCP: using update sequence 0
I (503) ESP_RADIO_SPINEL: spinel UART interface initialization completed
I (503) ESP_RADIO_SPINEL: Spinel UART interface has been successfully enabled
I (503) ESP_ZIGBEE_RADIO_SPINEL_UART: Spinel UART interface enable successfully
I(513) OPENTHREAD:[I] P-SpinelDrive-: co-processor reset: RESET_POWER_ON
E(523) OPENTHREAD:[C] P-SpinelDrive-: Software reset co-processor successfully
I (573) ESP_ZIGBEE_RCP: Running RCP version: openthread-esp32/fcae32885b029-b945928d7; esp32h2; 2026-03-11 02:30:22 UTC
```
## Gateway Functions
- If `CONFIG_AUTO_UPDATE_RCP` is enabled and the version does not match the stored one, the board will automatically update the RCP using the stored version.
* When the device starts up, it will attempt to connect to a Wi-Fi network and then interface with the OT-RCP via UART to form a Zigbee network.
* For more Gateway functionalities, please refer to [matter zigbee bridge](https://github.com/espressif/esp-matter/tree/main/examples/bridge_apps/zigbee_bridge/) and [Rainmaker Zigbee Gateway](https://github.com/espressif/esp-rainmaker/tree/master/examples/zigbee_gateway) examples.
- After confirming that the remote radio is functioning properly, the board will connect to Wi-Fi as configured in menuconfig.
```
I (573) example_connect: Start example_connect.
I (583) pp: pp rom version: e7ae62f
I (583) net80211: net80211 rom version: e7ae62f
I (593) wifi:wifi driver task: 3fcb86d0, prio:23, stack:6656, core=0
I (593) wifi:wifi firmware version: 14da9b7
I (593) wifi:wifi certification version: v7.0
I (603) wifi:config NVS flash: enabled
I (603) wifi:config nano formatting: disabled
I (603) wifi:Init data frame dynamic rx buffer num: 32
I (613) wifi:Init static rx mgmt buffer num: 5
I (613) wifi:Init management short buffer num: 32
I (623) wifi:Init dynamic tx buffer num: 32
I (623) wifi:Init static tx FG buffer num: 2
I (633) wifi:Init static rx buffer size: 1600
I (633) wifi:Init static rx buffer num: 10
I (633) wifi:Init dynamic rx buffer num: 32
I (643) wifi_init: rx ba win: 6
I (643) wifi_init: accept mbox: 6
I (643) wifi_init: tcpip mbox: 32
I (653) wifi_init: udp mbox: 6
I (653) wifi_init: tcp mbox: 6
I (653) wifi_init: tcp tx win: 5760
I (663) wifi_init: tcp rx win: 5760
I (663) wifi_init: tcp mss: 1440
I (663) wifi_init: WiFi IRAM OP enabled
I (673) wifi_init: WiFi RX IRAM OP enabled
I (673) phy_init: phy_version 701,f4f1da3a,Mar 3 2025,15:50:10
W (673) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
I (783) phy_init: Saving new calibration data due to checksum failure or outdated calibration data, mode(2)
I (793) wifi:mode : sta (48:27:e2:14:43:38)
I (793) wifi:enable tsf
I (793) example_connect: Connecting to esp-guest...
W (793) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (803) example_connect: Waiting for IP(s)
I (3293) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1, snd_ch_cfg:0x0
I (3303) wifi:state: init -> auth (0xb0)
I (3303) wifi:state: auth -> assoc (0x0)
I (3323) wifi:state: assoc -> run (0x10)
I (3413) wifi:connected with esp-guest, aid = 1, channel 6, BW20, bssid = 84:78:48:86:87:31
I (3423) wifi:security: WPA2-PSK, phy: bgn, rssi: -30
I (3423) wifi:pm start, type: 1
I (3423) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3433) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
I (3453) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (3503) wifi:<ba-add>idx:0 (ifx:0, 84:78:48:86:87:31), tid:0, ssn:0, winSize:64
I (4573) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:4a27:e2ff:fe14:4338, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (4843) esp_netif_handlers: example_netif_sta ip: 10.18.40.174, mask: 255.255.255.0, gw: 10.18.40.1
I (4843) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 10.18.40.174
I (4843) example_common: Connected to example_netif_sta
I (4853) example_common: - IPv4 address: 10.18.40.174,
I (4853) example_common: - IPv6 address: fe80:0000:0000:0000:4a27:e2ff:fe14:4338, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (4863) wifi:Set ps type: 0, coexist: 0
```
- Finally, the board will act as the `Zigbee Gateway`, forming a network and handling commands from the network.
```
I (4883) ZIGBEE_GATEWAY: Initialize Zigbee stack
I (4883) ZIGBEE_GATEWAY: Deferred driver initialization successful
I (4883) ZIGBEE_GATEWAY: Device started up in factory-reset mode
I (5303) ZIGBEE_GATEWAY: Formed network successfully: PAN ID(0x4494, EXT: 0x6055f9fffef7a2ad), Channel(13), Short Address(0x0000)
I (5573) ZIGBEE_GATEWAY: Network(0x4494) is open for 180 seconds
I (5573) ZIGBEE_GATEWAY: Network steering completed
```
- Gateway functionalities supporting Wi-Fi interaction will be added in future updates.
## Troubleshooting
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

@@ -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);
@@ -1,8 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1400K,
zb_storage, data, fat, 0x16e000,16K,
zb_fct, data, fat, 0x172000,1K,
rcp_fw, data, spiffs, 0x173000,500k,
nvs, data, nvs, , 0x6000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 1708K,
zb_fct, data, fat, , 1K,
rcp_fw, data, spiffs, , 640k,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000, nvs, data, nvs, , 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000, otadata, data, ota, , 0x2000,
5 factory, app, factory, 0x10000, 1400K, phy_init, data, phy, , 0x1000,
6 zb_storage, data, fat, 0x16e000,16K, factory, app, factory, , 1708K,
7 zb_fct, data, fat, 0x172000,1K, zb_fct, data, fat, , 1K,
8 rcp_fw, data, spiffs, 0x173000,500k, rcp_fw, data, spiffs, , 640k,
@@ -8,12 +8,28 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
#
# Serial flasher config
#
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# end of Serial flasher config
#
# Zboss
# Event
#
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
#end of Event
#
# Zigbee
#
CONFIG_ZB_ENABLED=y
CONFIG_ZB_ZCZR=y
# end of Zboss
# end of Component config
# end of Zigbee
#
# ESP Zigbee gateway RCP update
#
CONFIG_AUTO_UPDATE_RCP=n
# end of ESP Zigbee gateway RCP update