Skip to content

Commit 7ff80d6

Browse files
committed
feat(zigbee): Add ZigbeeGateway endpoint support
1 parent 5cc8f9c commit 7ff80d6

File tree

8 files changed

+263
-2
lines changed

8 files changed

+263
-2
lines changed
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,ZigbeeMode=zczr",
3+
"requires": [
4+
"CONFIG_ZB_ENABLED=y"
5+
],
6+
"targets": {
7+
"esp32c6": false,
8+
"esp32h2": false
9+
}
10+
}

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

+19
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,25 @@ 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+
.baud_rate = 460800, \
72+
.data_bits = UART_DATA_8_BITS, \
73+
.parity = UART_PARITY_DISABLE, \
74+
.stop_bits = UART_STOP_BITS_1, \
75+
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
76+
.rx_flow_ctrl_thresh = 0, \
77+
.source_clk = UART_SCLK_DEFAULT, \
78+
}, \
79+
}, \
80+
}
81+
6382
class ZigbeeCore {
6483
private:
6584
esp_zb_radio_config_t _radio_config;
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "ZigbeeGateway.h"
2+
#if CONFIG_ZB_ENABLED
3+
4+
ZigbeeGateway::ZigbeeGateway(uint8_t endpoint) : ZigbeeEP(endpoint) {
5+
_device_id = ESP_ZB_HA_HOME_GATEWAY_DEVICE_ID;
6+
7+
_cluster_list = esp_zb_zcl_cluster_list_create();
8+
esp_zb_cluster_list_add_basic_cluster(_cluster_list, esp_zb_basic_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
9+
esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_identify_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
10+
esp_zb_cluster_list_add_identify_cluster(_cluster_list, esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY), ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
11+
12+
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_HOME_GATEWAY_DEVICE_ID, .app_device_version = 0};
13+
}
14+
15+
#endif // CONFIG_ZB_ENABLED
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* Class of Zigbee Gateway endpoint inherited from common EP class */
2+
3+
#pragma once
4+
5+
#include "soc/soc_caps.h"
6+
#include "sdkconfig.h"
7+
#if CONFIG_ZB_ENABLED
8+
9+
#include "ZigbeeEP.h"
10+
#include "ha/esp_zigbee_ha_standard.h"
11+
12+
class ZigbeeGateway : public ZigbeeEP {
13+
public:
14+
ZigbeeGateway(uint8_t endpoint);
15+
~ZigbeeGateway() {}
16+
};
17+
18+
#endif // CONFIG_ZB_ENABLED

0 commit comments

Comments
 (0)