Skip to content

Commit 923da95

Browse files
P-R-O-C-H-Ypre-commit-ci-lite[bot]SuGlider
authored
feat(zigbee): Add ZigbeeGateway endpoint support + Time Cluster bugfix (#11009)
* fix(zigbee): Remove the need of native ieee802154 radio * feat(zigbee): Add ZigbeeGateway endpoint support * fix(zigbee): Fix TimeCluster missing status attribute * feat(zigbee): Add new src to CMakeLists * feaz(zigbee): Update keywords.txt with latest updates * feat(zigbee): Add 8MB Zigbee ZCZR partitions to other socs * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Rodrigo Garcia <[email protected]>
1 parent 7485c65 commit 923da95

13 files changed

+341
-6
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS
297297
libraries/Zigbee/src/ep/ZigbeeVibrationSensor.cpp
298298
libraries/Zigbee/src/ep/ZigbeeAnalog.cpp
299299
libraries/Zigbee/src/ep/ZigbeeRangeExtender.cpp
300+
libraries/Zigbee/src/ep/ZigbeeGateway.cpp
300301
)
301302

302303
set(ARDUINO_LIBRARY_BLE_SRCS

boards.txt

+12
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,9 @@ esp32s3.menu.PartitionScheme.esp_sr_16.build.partitions=esp_sr_16
947947
esp32s3.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
948948
esp32s3.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
949949
esp32s3.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
950+
esp32s3.menu.PartitionScheme.zigbee_zczr_8MB=Zigbee ZCZR 8MB with spiffs
951+
esp32s3.menu.PartitionScheme.zigbee_zczr_8MB.build.partitions=zigbee_zczr_8MB
952+
esp32s3.menu.PartitionScheme.zigbee_zczr_8MB.upload.maximum_size=3407872
950953
esp32s3.menu.PartitionScheme.custom=Custom
951954
esp32s3.menu.PartitionScheme.custom.build.partitions=
952955
esp32s3.menu.PartitionScheme.custom.upload.maximum_size=16777216
@@ -1108,6 +1111,9 @@ esp32c3.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480
11081111
esp32c3.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
11091112
esp32c3.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
11101113
esp32c3.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
1114+
esp32c3.menu.PartitionScheme.zigbee_zczr_8MB=Zigbee ZCZR 8MB with spiffs
1115+
esp32c3.menu.PartitionScheme.zigbee_zczr_8MB.build.partitions=zigbee_zczr_8MB
1116+
esp32c3.menu.PartitionScheme.zigbee_zczr_8MB.upload.maximum_size=3407872
11111117
esp32c3.menu.PartitionScheme.custom=Custom
11121118
esp32c3.menu.PartitionScheme.custom.build.partitions=
11131119
esp32c3.menu.PartitionScheme.custom.upload.maximum_size=16777216
@@ -1313,6 +1319,9 @@ esp32s2.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480
13131319
esp32s2.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
13141320
esp32s2.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
13151321
esp32s2.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
1322+
esp32s2.menu.PartitionScheme.zigbee_zczr_8MB=Zigbee ZCZR 8MB with spiffs
1323+
esp32s2.menu.PartitionScheme.zigbee_zczr_8MB.build.partitions=zigbee_zczr_8MB
1324+
esp32s2.menu.PartitionScheme.zigbee_zczr_8MB.upload.maximum_size=3407872
13161325
esp32s2.menu.PartitionScheme.custom=Custom
13171326
esp32s2.menu.PartitionScheme.custom.build.partitions=
13181327
esp32s2.menu.PartitionScheme.custom.upload.maximum_size=16777216
@@ -1493,6 +1502,9 @@ esp32.menu.PartitionScheme.rainmaker_8MB.upload.maximum_size=4116480
14931502
esp32.menu.PartitionScheme.zigbee_zczr=Zigbee ZCZR 4MB with spiffs
14941503
esp32.menu.PartitionScheme.zigbee_zczr.build.partitions=zigbee_zczr
14951504
esp32.menu.PartitionScheme.zigbee_zczr.upload.maximum_size=1310720
1505+
esp32.menu.PartitionScheme.zigbee_zczr_8MB=Zigbee ZCZR 8MB with spiffs
1506+
esp32.menu.PartitionScheme.zigbee_zczr_8MB.build.partitions=zigbee_zczr_8MB
1507+
esp32.menu.PartitionScheme.zigbee_zczr_8MB.upload.maximum_size=3407872
14961508
esp32.menu.PartitionScheme.custom=Custom
14971509
esp32.menu.PartitionScheme.custom.build.partitions=
14981510
esp32.menu.PartitionScheme.custom.upload.maximum_size=16777216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Arduino-ESP32 Zigbee Gateway Example
2+
3+
This example shows how to configure Zigbee Gateway device, running on SoCs without native IEEE 802.15.4.
4+
5+
# Supported Targets
6+
7+
Currently, this example supports the following targets.
8+
9+
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
10+
| ----------------- | ----- | -------- | -------- | -------- |
11+
12+
## Hardware Required
13+
14+
* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee Radio Co-processor loaded with [ot_rcp example](https://github.com/espressif/esp-idf/tree/master/examples/openthread/ot_rcp).
15+
* A USB cable for power supply and programming.
16+
* Choose another board from supported targets as Zigbee coordinator/router and upload the Zigbee_Gateway example.
17+
18+
### Configure the Project
19+
20+
Set the RCP connection (UART) by changing the `GATEWAY_RCP_UART_PORT`, `GATEWAY_RCP_RX_PIN` and `GATEWAY_RCP_TX_PIN` definition.
21+
22+
#### Using Arduino IDE
23+
24+
To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits).
25+
26+
* Before Compile/Verify, select the correct board: `Tools -> Board`.
27+
* Select the Coordinator Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`.
28+
* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`.
29+
* Select the COM port: `Tools -> Port: xxx where the `xxx` is the detected COM port.
30+
* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`.
31+
32+
## Troubleshooting
33+
34+
* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`.
35+
36+
By default, the coordinator network is closed after rebooting or flashing new firmware.
37+
To open the network you have 2 options:
38+
39+
* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`.
40+
* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join.
41+
42+
***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
43+
44+
* **LED not blinking:** Check the wiring connection and the IO selection.
45+
* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed.
46+
* **COM port not detected:** Check the USB cable and the USB to Serial driver installation.
47+
48+
If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute).
49+
50+
## Contribute
51+
52+
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
53+
54+
If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome!
55+
56+
Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else.
57+
58+
## Resources
59+
60+
* Official ESP32 Forum: [Link](https://esp32.com)
61+
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
62+
* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
63+
* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf)
64+
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @brief This example demonstrates simple Zigbee Gateway functionality.
17+
*
18+
* The example demonstrates how to use Zigbee library on ESP32s to create a Zigbee Gateway, updating the time from NTP server.
19+
* The Gateway is able to communicate with Zigbee end devices and send/receive data to/from them.
20+
* The Gateway is also able to communicate with the cloud or other devices over Wi-Fi / BLE.
21+
*
22+
* Proper Zigbee mode must be selected in Tools->Zigbee mode->Zigbee ZCZR (coordinator/router)
23+
* and also the correct partition scheme must be selected in Tools->Partition Scheme->Zigbee ZCZR
24+
*
25+
* Please check the README.md for instructions and more detailed description.
26+
*
27+
* Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
28+
*/
29+
30+
#ifndef ZIGBEE_MODE_ZCZR
31+
#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
32+
#endif
33+
34+
#include "Zigbee.h"
35+
#include <WiFi.h>
36+
#include "time.h"
37+
#include "esp_sntp.h"
38+
39+
/* Zigbee gateway configuration */
40+
#define GATEWAY_ENDPOINT_NUMBER 1
41+
#define GATEWAY_RCP_UART_PORT UART_NUM_1 // UART 0 is used for Serial communication
42+
#define GATEWAY_RCP_RX_PIN 4
43+
#define GATEWAY_RCP_TX_PIN 5
44+
45+
ZigbeeGateway zbGateway = ZigbeeGateway(GATEWAY_ENDPOINT_NUMBER);
46+
47+
/* Wi-Fi credentials */
48+
const char *ssid = "your-ssid";
49+
const char *password = "your-password";
50+
51+
/* NTP server configuration */
52+
const char *ntpServer1 = "pool.ntp.org";
53+
const char *ntpServer2 = "time.nist.gov";
54+
const long gmtOffset_sec = 3600;
55+
const int daylightOffset_sec = 3600;
56+
const char *time_zone = "CET-1CEST,M3.5.0,M10.5.0/3"; // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)
57+
58+
/* Time structure */
59+
struct tm timeinfo;
60+
61+
/********************* Arduino functions **************************/
62+
void setup() {
63+
Serial.begin(115200);
64+
65+
// Initialize Wi-Fi and connect to AP
66+
WiFi.begin(ssid, password);
67+
esp_sntp_servermode_dhcp(1); // (optional)
68+
69+
Serial.print("Connecting to WiFi");
70+
71+
while (WiFi.status() != WL_CONNECTED) {
72+
delay(500);
73+
Serial.print(".");
74+
}
75+
Serial.println("WiFi connected");
76+
77+
// Initialize Zigbee and Begin Zigbee stack
78+
// Optional: set Zigbee device name and model
79+
zbGateway.setManufacturerAndModel("Espressif", "ZigbeeGateway");
80+
zbGateway.addTimeCluster(timeinfo, gmtOffset_sec);
81+
82+
// Add endpoint to Zigbee Core
83+
Serial.println("Adding Zigbee Gateway endpoint");
84+
Zigbee.addEndpoint(&zbGateway);
85+
86+
// Optional: Open network for 180 seconds after boot
87+
Zigbee.setRebootOpenNetwork(180);
88+
89+
// Set custom radio configuration for RCP communication
90+
esp_zb_radio_config_t radio_config = ZIGBEE_DEFAULT_UART_RCP_RADIO_CONFIG();
91+
radio_config.radio_uart_config.port = GATEWAY_RCP_UART_PORT;
92+
radio_config.radio_uart_config.rx_pin = (gpio_num_t)GATEWAY_RCP_RX_PIN;
93+
radio_config.radio_uart_config.tx_pin = (gpio_num_t)GATEWAY_RCP_TX_PIN;
94+
95+
Zigbee.setRadioConfig(radio_config);
96+
97+
// When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR or ZIGBEE_ROUTER mode
98+
if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
99+
Serial.println("Zigbee failed to start!");
100+
Serial.println("Rebooting...");
101+
ESP.restart();
102+
}
103+
104+
// set notification call-back function
105+
sntp_set_time_sync_notification_cb(timeavailable);
106+
sntp_set_sync_interval(30000); // sync every 30 seconds
107+
108+
// config time zone and NTP servers
109+
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
110+
}
111+
112+
void loop() {
113+
// Nothing to do here in this example
114+
}
115+
116+
void printLocalTime() {
117+
if (!getLocalTime(&timeinfo)) {
118+
Serial.println("No time available (yet)");
119+
return;
120+
}
121+
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
122+
zbGateway.setTime(timeinfo);
123+
Serial.println("Time updated in Zigbee Gateway");
124+
}
125+
126+
// Callback function (gets called when time adjusts via NTP)
127+
void timeavailable(struct timeval *t) {
128+
Serial.println("Got time adjustment from NTP!");
129+
printLocalTime();
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"fqbn_append": "PartitionScheme=zigbee_zczr_8MB,ZigbeeMode=zczr",
3+
"requires": [
4+
"CONFIG_ZB_ENABLED=y"
5+
],
6+
"targets": {
7+
"esp32c6": false,
8+
"esp32h2": false
9+
}
10+
}

libraries/Zigbee/keywords.txt

+48-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,22 @@ ZigbeeThermostat KEYWORD1
2121
ZigbeeFlowSensor KEYWORD1
2222
ZigbeePressureSensor KEYWORD1
2323
ZigbeeOccupancySensor KEYWORD1
24+
ZigbeeAnalog KEYWORD1
25+
ZigbeeCarbonDioxideSensor KEYWORD1
26+
ZigbeeContactSwitch KEYWORD1
27+
ZigbeeDoorWindowHandle KEYWORD1
28+
ZigbeeGateway KEYWORD1
29+
ZigbeeRangeExtender KEYWORD1
30+
ZigbeeVibrationSensor KEYWORD1
31+
ZigbeeWindowCovering KEYWORD1
2432

2533
# Other
2634
zigbee_role_t KEYWORD1
2735
zbstring_t KEYWORD1
2836
zb_device_params_t KEYWORD1
2937
zigbee_scan_result_t KEYWORD1
38+
zb_power_source_t KEYWORD1
39+
ZigbeeWindowCoveringType KEYWORD1
3040

3141
#######################################
3242
# Methods and Functions (KEYWORD2)
@@ -126,6 +136,43 @@ setSensorType KEYWORD2
126136
# ZigbeeCarbonDioxideSensor
127137
setCarbonDioxide KEYWORD2
128138

139+
# ZigbeeAnalog
140+
addAnalogValue KEYWORD2
141+
addAnalogInput KEYWORD2
142+
addAnalogOutput KEYWORD2
143+
onAnalogOutputChange KEYWORD2
144+
setAnalogValue KEYWORD2
145+
setAnalogInput KEYWORD2
146+
reportAnalogInput KEYWORD2
147+
setAnalogInputReporting KEYWORD2
148+
149+
# ZigbeeCarbonDioxideSensor
150+
setCarbonDioxide KEYWORD2
151+
152+
# ZigbeeContactSwitch + ZigbeeDoorWindowHandle
153+
setIASClientEndpoint KEYWORD2
154+
setClosed KEYWORD2
155+
setOpen KEYWORD2
156+
setTilted KEYWORD2
157+
158+
# ZigbeeVibrationSensor
159+
setVibration KEYWORD2
160+
161+
ZigbeeWindowCovering
162+
onOpen KEYWORD2
163+
onClose KEYWORD2
164+
onGoToLiftPercentage KEYWORD2
165+
onGoToTiltPercentage KEYWORD2
166+
onStop KEYWORD2
167+
setLiftPosition KEYWORD2
168+
setLiftPercentage KEYWORD2
169+
setTiltPosition KEYWORD2
170+
setTiltPercentage KEYWORD2
171+
setCoveringType KEYWORD2
172+
setConfigStatus KEYWORD2
173+
setMode KEYWORD2
174+
setLimits KEYWORD2
175+
129176
#######################################
130177
# Constants (LITERAL1)
131178
#######################################
@@ -137,7 +184,6 @@ ZIGBEE_DEFAULT_ED_CONFIG LITERAL1
137184
ZIGBEE_DEFAULT_ROUTER_CONFIG LITERAL1
138185
ZIGBEE_DEFAULT_COORDINATOR_CONFIG LITERAL1
139186
ZIGBEE_DEFAULT_RADIO_CONFIG LITERAL1
187+
ZIGBEE_DEFAULT_UART_RCP_RADIO_CONFIG LITERAL1
140188
ZIGBEE_DEFAULT_HOST_CONFIG LITERAL1
141189
ZB_ARRAY_LENTH LITERAL1
142-
XYZ_TO_RGB LITERAL1
143-
RGB_TO_XYZ LITERAL1

libraries/Zigbee/src/Zigbee.h

+1
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@
2424
#include "ep/ZigbeeWindowCovering.h"
2525
#include "ep/ZigbeeVibrationSensor.h"
2626
#include "ep/ZigbeeRangeExtender.h"
27+
#include "ep/ZigbeeGateway.h"

libraries/Zigbee/src/ZigbeeCore.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ void ZigbeeCore::addEndpoint(ZigbeeEP *ep) {
8787
return;
8888
}
8989

90-
esp_zb_ep_list_add_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config);
90+
if (ep->_device_id == ESP_ZB_HA_HOME_GATEWAY_DEVICE_ID) {
91+
esp_zb_ep_list_add_gateway_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config);
92+
} else {
93+
esp_zb_ep_list_add_ep(_zb_ep_list, ep->_cluster_list, ep->_ep_config);
94+
}
9195
}
9296

9397
static void esp_zb_task(void *pvParameters) {
@@ -156,7 +160,7 @@ bool ZigbeeCore::zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs) {
156160
}
157161

158162
// Create Zigbee task and start Zigbee stack
159-
xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
163+
xTaskCreate(esp_zb_task, "Zigbee_main", 8192, NULL, 5, NULL);
160164

161165
return true;
162166
}

libraries/Zigbee/src/ZigbeeCore.h

+20
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@ typedef enum {
6060
} \
6161
}
6262

63+
#define ZIGBEE_DEFAULT_UART_RCP_RADIO_CONFIG() \
64+
{ \
65+
.radio_mode = ZB_RADIO_MODE_UART_RCP, \
66+
.radio_uart_config = { \
67+
.port = UART_NUM_1, \
68+
.rx_pin = GPIO_NUM_NC, \
69+
.tx_pin = GPIO_NUM_NC, \
70+
.uart_config = \
71+
{ \
72+
.baud_rate = 460800, \
73+
.data_bits = UART_DATA_8_BITS, \
74+
.parity = UART_PARITY_DISABLE, \
75+
.stop_bits = UART_STOP_BITS_1, \
76+
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
77+
.rx_flow_ctrl_thresh = 0, \
78+
.source_clk = UART_SCLK_DEFAULT, \
79+
}, \
80+
}, \
81+
}
82+
6383
class ZigbeeCore {
6484
private:
6585
esp_zb_radio_config_t _radio_config;

0 commit comments

Comments
 (0)