Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 542274d

Browse files
P-R-O-C-H-Ypre-commit-ci-lite[bot]
andauthoredMay 27, 2025··
feat(zigbee): Remove static variables, improve binding, new example (#11316)
* feat(zigbee): Remove static variables, improve binding, new example * feat(example): Add missing header * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 9090b46 commit 542274d

File tree

13 files changed

+862
-102
lines changed

13 files changed

+862
-102
lines changed
 
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Arduino-ESP32 Zigbee Multi-Switch Example
2+
3+
This example demonstrates how to configure a Zigbee device as a multi-switch controller that can control up to three different Zigbee lights independently. The switch can operate in either coordinator or router mode, making it compatible with Home Assistant integration.
4+
5+
# Supported Targets
6+
7+
Currently, this example supports the following targets.
8+
9+
| Supported Targets | ESP32-C6 | ESP32-H2 |
10+
| ----------------- | -------- | -------- |
11+
12+
## Hardware Required
13+
14+
* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee multi-switch controller
15+
* One or more Zigbee light devices (loaded with Zigbee_On_Off_Light example)
16+
* A USB cable for power supply and programming
17+
18+
### Configure the Project
19+
20+
The example uses the BOOT button (pin 9) on ESP32-C6 and ESP32-H2 as the physical switch input. The switch can be configured to operate in two modes:
21+
22+
1. **Coordinator Mode**: For running your own Zigbee network
23+
2. **Router Mode**: For Home Assistant integration
24+
25+
#### Using Arduino IDE
26+
27+
To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits).
28+
29+
* Before Compile/Verify, select the correct board: `Tools -> Board`
30+
* Select the Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)`
31+
* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`
32+
* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port
33+
* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`
34+
35+
## Features
36+
37+
The multi-switch example provides the following functionality:
38+
39+
1. **Light Configuration**
40+
- Configure up to 3 different lights using their endpoint and IEEE address
41+
- Configuration is stored in NVS (Non-Volatile Storage) and persists after power loss
42+
- Remove configured lights when needed
43+
44+
2. **Control Commands**
45+
- Control all bound lights simultaneously:
46+
- Turn all bound lights ON
47+
- Turn all bound lights OFF
48+
- Toggle all bound lights
49+
- Control individual lights (1-3):
50+
- Turn light ON
51+
- Turn light OFF
52+
- Toggle light
53+
54+
3. **Network Management**
55+
- Factory reset capability
56+
- Open network for device joining
57+
- View bound devices and current light configurations
58+
59+
## Serial Commands
60+
61+
The example accepts the following commands through the serial interface:
62+
63+
* `config` - Configure a new light (requires light number, endpoint, and IEEE address)
64+
* `remove` - Remove a configured light
65+
* `on` - Turn all bound lights ON
66+
* `off` - Turn all bound lights OFF
67+
* `toggle` - Toggle all bound lights
68+
* `1on`, `2on`, `3on` - Turn individual light ON
69+
* `1off`, `2off`, `3off` - Turn individual light OFF
70+
* `1toggle`, `2toggle`, `3toggle` - Toggle individual light
71+
* `freset` - Perform factory reset
72+
* `open_network` - Open network for device joining (only for coordinator role)
73+
74+
## Troubleshooting
75+
76+
If the End device flashed with the example `Zigbee_On_Off_Light` is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator.
77+
You can do the following:
78+
79+
* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`
80+
* In the `Zigbee_On_Off_Light` example sketch call `Zigbee.factoryReset()`
81+
82+
By default, the coordinator network is closed after rebooting or flashing new firmware.
83+
To open the network you have 2 options:
84+
85+
* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time)` before calling `Zigbee.begin()`
86+
* In application you can anytime call `Zigbee.openNetwork(time)` to open the network for devices to join
87+
88+
***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
89+
90+
* **LED not blinking:** Check the wiring connection and the IO selection
91+
* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed
92+
* **COM port not detected:** Check the USB cable and the USB to Serial driver installation
93+
94+
If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute).
95+
96+
## Contribute
97+
98+
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
99+
100+
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!
101+
102+
Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else.
103+
104+
## Resources
105+
106+
* Official ESP32 Forum: [Link](https://esp32.com)
107+
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
108+
* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
109+
* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf)
110+
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
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 multi-light switch.
17+
*
18+
* The example demonstrates how to use Zigbee library to control multiple light bulbs.
19+
* The light bulbs are Zigbee devices, which are controlled by a Zigbee coordinator/router (Multi-Switch).
20+
* Settings are stored in NVS to not be lost after power loss.
21+
* Configuring and controlling the lights is done via serial input.
22+
*
23+
* Proper Zigbee mode must be selected in Tools->Zigbee mode
24+
* and also the correct partition scheme must be selected in Tools->Partition Scheme.
25+
*
26+
* Please check the README.md for instructions and more detailed description.
27+
*
28+
* Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
29+
*/
30+
31+
#ifndef ZIGBEE_MODE_ZCZR
32+
#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
33+
#endif
34+
35+
#include "Zigbee.h"
36+
#include <Preferences.h>
37+
38+
#define ZIGBEE_ROLE ZIGBEE_ROUTER // ZIGBEE_ROUTER for HomeAssistant integration, ZIGBEE_COORDINATOR for running own network
39+
40+
/* Zigbee switch configuration */
41+
#define SWITCH_ENDPOINT_NUMBER 1
42+
43+
uint8_t button = BOOT_PIN;
44+
45+
ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);
46+
47+
int buttonState;
48+
int lastButtonState = LOW;
49+
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
50+
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
51+
52+
// To be stored in NVS to not be lost after power loss
53+
Preferences prefs;
54+
55+
zb_device_params_t light_1;
56+
zb_device_params_t light_2;
57+
zb_device_params_t light_3;
58+
59+
void storeLightParams(zb_device_params_t *light, int light_number) {
60+
char key[10];
61+
snprintf(key, sizeof(key), "light_%d", light_number);
62+
prefs.putBytes(key, light, sizeof(zb_device_params_t));
63+
}
64+
65+
void loadLightParams(zb_device_params_t *light, int light_number) {
66+
char key[10];
67+
snprintf(key, sizeof(key), "light_%d", light_number);
68+
prefs.getBytes(key, light, sizeof(zb_device_params_t));
69+
}
70+
71+
/********************* Arduino functions **************************/
72+
void setup() {
73+
Serial.begin(115200);
74+
75+
// Initialize Preferences
76+
prefs.begin("lights", false); // false means read/write mode
77+
78+
// Load saved light parameters
79+
loadLightParams(&light_1, 1);
80+
loadLightParams(&light_2, 2);
81+
loadLightParams(&light_3, 3);
82+
83+
// Init button switch
84+
pinMode(button, INPUT_PULLUP);
85+
86+
// Set Zigbee device name and model
87+
zbSwitch.setManufacturerAndModel("Espressif", "ZBMultiSwitch");
88+
89+
// Set binding settings depending on the role
90+
if (ZIGBEE_ROLE == ZIGBEE_COORDINATOR) {
91+
zbSwitch.allowMultipleBinding(true); // To allow binding multiple lights to the switch
92+
} else {
93+
zbSwitch.setManualBinding(true); //Set manual binding to true, so binding is done on Home Assistant side
94+
}
95+
96+
// Add endpoint to Zigbee Core
97+
Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core");
98+
Zigbee.addEndpoint(&zbSwitch);
99+
100+
// When all EPs are registered, start Zigbee with given role
101+
if (!Zigbee.begin(ZIGBEE_ROLE)) {
102+
Serial.println("Zigbee failed to start!");
103+
Serial.println("Rebooting...");
104+
ESP.restart();
105+
}
106+
107+
Serial.println("Connecting to network");
108+
while (!Zigbee.connected()) {
109+
Serial.print(".");
110+
delay(100);
111+
}
112+
Serial.println();
113+
}
114+
115+
void loop() {
116+
// Handle button switch in loop()
117+
if (digitalRead(button) == LOW) { // Push button pressed
118+
// Key debounce handling
119+
while (digitalRead(button) == LOW) {
120+
delay(50);
121+
}
122+
// Print bound devices
123+
Serial.println("Bound devices:");
124+
zbSwitch.printBoundDevices(Serial);
125+
Serial.println("Lights configured:");
126+
Serial.printf("Light 1: %d %s\n", light_1.endpoint, Zigbee.formatIEEEAddress(light_1.ieee_addr));
127+
Serial.printf("Light 2: %d %s\n", light_2.endpoint, Zigbee.formatIEEEAddress(light_2.ieee_addr));
128+
Serial.printf("Light 3: %d %s\n", light_3.endpoint, Zigbee.formatIEEEAddress(light_3.ieee_addr));
129+
}
130+
// Handle serial input to configure and control the lights
131+
if (Serial.available()) {
132+
String command = Serial.readString();
133+
Serial.println("Command: " + command);
134+
135+
if (command == "config") {
136+
//wait for light number, endpoint and ieee address
137+
Serial.println("Enter light number (1-3):");
138+
while (!Serial.available()) {
139+
delay(100);
140+
}
141+
int light_number = Serial.parseInt();
142+
Serial.println("Enter endpoint:");
143+
while (!Serial.available()) {
144+
delay(100);
145+
}
146+
int endpoint = Serial.parseInt();
147+
Serial.println("Enter ieee address:");
148+
while (!Serial.available()) {
149+
delay(100);
150+
}
151+
String ieee_address = Serial.readStringUntil('\n');
152+
ieee_address.trim();
153+
//convert ieee address to uint8_t array (format in string is 00:00:00:00:00:00:00:00)
154+
uint8_t ieee_address_array[8];
155+
int index = 0;
156+
bool valid = true;
157+
158+
// Check if the string has the correct format (8 hex pairs with colons)
159+
if (ieee_address.length() != 23) { // 8 pairs * 2 + 7 colons
160+
Serial.println("Invalid IEEE address format. Expected format: 00:00:00:00:00:00:00:00");
161+
valid = false;
162+
} else {
163+
for (int i = 0; i < ieee_address.length() && index < 8 && valid; i += 3) {
164+
// Check for colon at expected positions
165+
if (i > 0 && ieee_address.charAt(i - 1) != ':') {
166+
valid = false;
167+
break;
168+
}
169+
// Convert two hex characters to a byte
170+
char hex[3] = {ieee_address.charAt(i), ieee_address.charAt(i + 1), '\0'};
171+
char *endptr;
172+
long value = strtol(hex, &endptr, 16);
173+
if (*endptr != '\0' || value < 0 || value > 255) {
174+
valid = false;
175+
break;
176+
}
177+
// Store bytes in reverse order to match Zigbee standard
178+
ieee_address_array[7 - index++] = (uint8_t)value;
179+
}
180+
}
181+
182+
if (!valid || index != 8) {
183+
Serial.println("Invalid IEEE address. Please enter a valid address in format: 00:00:00:00:00:00:00:00");
184+
return;
185+
}
186+
//set the light parameters
187+
if (light_number == 1) {
188+
light_1.endpoint = endpoint;
189+
memcpy(light_1.ieee_addr, ieee_address_array, 8);
190+
storeLightParams(&light_1, 1);
191+
} else if (light_number == 2) {
192+
light_2.endpoint = endpoint;
193+
memcpy(light_2.ieee_addr, ieee_address_array, 8);
194+
storeLightParams(&light_2, 2);
195+
} else if (light_number == 3) {
196+
light_3.endpoint = endpoint;
197+
memcpy(light_3.ieee_addr, ieee_address_array, 8);
198+
storeLightParams(&light_3, 3);
199+
}
200+
Serial.printf("Light %d configured\n", light_number);
201+
} else if (command == "remove") {
202+
//wait for light number
203+
Serial.println("Enter light number (1-3):");
204+
while (!Serial.available()) {
205+
delay(100);
206+
}
207+
int light_number = Serial.parseInt();
208+
uint8_t ieee_address_empty[8] = {0, 0, 0, 0, 0, 0, 0, 0};
209+
if (light_number == 1) {
210+
light_1.endpoint = 0;
211+
memcpy(light_1.ieee_addr, ieee_address_empty, 8);
212+
storeLightParams(&light_1, 1);
213+
} else if (light_number == 2) {
214+
light_2.endpoint = 0;
215+
memcpy(light_2.ieee_addr, ieee_address_empty, 8);
216+
storeLightParams(&light_2, 2);
217+
} else if (light_number == 3) {
218+
light_3.endpoint = 0;
219+
memcpy(light_3.ieee_addr, ieee_address_empty, 8);
220+
storeLightParams(&light_3, 3);
221+
}
222+
Serial.printf("Light %d removed\n", light_number);
223+
} else if (command == "on") {
224+
Serial.println(" --> SIG Input : All Lights ON");
225+
zbSwitch.lightOn();
226+
} else if (command == "off") {
227+
Serial.println(" --> SIG Input : All Lights OFF");
228+
zbSwitch.lightOff();
229+
} else if (command == "toggle") {
230+
Serial.println(" --> SIG Input : All Lights Toggle");
231+
zbSwitch.lightToggle();
232+
} else if (command == "1on") {
233+
Serial.println(" --> SIG Input : Light 1 ON");
234+
zbSwitch.lightOn(light_1.endpoint, light_1.ieee_addr);
235+
} else if (command == "1off") {
236+
Serial.println(" --> SIG Input : Light 1 OFF");
237+
zbSwitch.lightOff(light_1.endpoint, light_1.ieee_addr);
238+
} else if (command == "1toggle") {
239+
Serial.println(" --> SIG Input : Light 1 Toggle");
240+
zbSwitch.lightToggle(light_1.endpoint, light_1.ieee_addr);
241+
} else if (command == "2on") {
242+
Serial.println(" --> SIG Input : Light 2 ON");
243+
zbSwitch.lightOn(light_2.endpoint, light_2.ieee_addr);
244+
} else if (command == "2off") {
245+
Serial.println(" --> SIG Input : Light 2 OFF");
246+
zbSwitch.lightOff(light_2.endpoint, light_2.ieee_addr);
247+
} else if (command == "2toggle") {
248+
Serial.println(" --> SIG Input : Light 2 Toggle");
249+
zbSwitch.lightToggle(light_2.endpoint, light_2.ieee_addr);
250+
} else if (command == "3on") {
251+
Serial.println(" --> SIG Input : Light 3 ON");
252+
zbSwitch.lightOn(light_3.endpoint, light_3.ieee_addr);
253+
} else if (command == "3off") {
254+
Serial.println(" --> SIG Input : Light 3 OFF");
255+
zbSwitch.lightOff(light_3.endpoint, light_3.ieee_addr);
256+
} else if (command == "3toggle") {
257+
Serial.println(" --> SIG Input : Light 3 Toggle");
258+
zbSwitch.lightToggle(light_3.endpoint, light_3.ieee_addr);
259+
} else if (command == "freset") {
260+
Serial.println(" --> SIG Input : Factory Reset!");
261+
delay(1500);
262+
Zigbee.factoryReset();
263+
} else if (command == "open_network") {
264+
Serial.println(" --> SIG Input : Open Network");
265+
if (ZIGBEE_ROLE == ZIGBEE_COORDINATOR) {
266+
Zigbee.openNetwork(180);
267+
} else {
268+
Serial.println("Open network is only available for coordinator role");
269+
}
270+
} else {
271+
Serial.println("Unknown command");
272+
}
273+
}
274+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr",
3+
"requires": [
4+
"CONFIG_SOC_IEEE802154_SUPPORTED=y"
5+
]
6+
}

‎libraries/Zigbee/src/ZigbeeCore.cpp

Lines changed: 254 additions & 43 deletions
Large diffs are not rendered by default.

‎libraries/Zigbee/src/ZigbeeCore.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "esp_zigbee_core.h"
1010
#include "zdo/esp_zigbee_zdo_common.h"
11+
#include "aps/esp_zigbee_aps.h"
1112
#include <esp32-hal-log.h>
1213
#include <list>
1314
#include "ZigbeeEP.h"
@@ -100,6 +101,7 @@ class ZigbeeCore {
100101
uint8_t _open_network;
101102
zigbee_scan_result_t *_scan_result;
102103
SemaphoreHandle_t lock;
104+
bool _debug;
103105

104106
bool zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs);
105107
static void scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor);
@@ -156,6 +158,7 @@ class ZigbeeCore {
156158
}
157159
void setRebootOpenNetwork(uint8_t time);
158160
void openNetwork(uint8_t time);
161+
void closeNetwork();
159162

160163
//scan_duration Time spent scanning each channel, in units of ((1 << scan_duration) + 1) * a beacon time. (15.36 microseconds)
161164
void scanNetworks(uint32_t channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK, uint8_t scan_duration = 5);
@@ -166,8 +169,29 @@ class ZigbeeCore {
166169

167170
void factoryReset(bool restart = true);
168171

172+
void setDebugMode(bool debug) {
173+
_debug = debug;
174+
}
175+
bool getDebugMode() {
176+
return _debug;
177+
}
178+
169179
// Friend function declaration to allow access to private members
170180
friend void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct);
181+
friend bool zb_apsde_data_indication_handler(esp_zb_apsde_data_ind_t ind);
182+
183+
// Helper functions for formatting addresses
184+
static inline const char *formatIEEEAddress(const esp_zb_ieee_addr_t addr) {
185+
static char buf[24];
186+
snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", addr[7], addr[6], addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
187+
return buf;
188+
}
189+
190+
static inline const char *formatShortAddress(uint16_t addr) {
191+
static char buf[7];
192+
snprintf(buf, sizeof(buf), "0x%04X", addr);
193+
return buf;
194+
}
171195
};
172196

173197
extern ZigbeeCore Zigbee;

‎libraries/Zigbee/src/ZigbeeEP.cpp

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@
77
#include "esp_zigbee_cluster.h"
88
#include "zcl/esp_zigbee_zcl_power_config.h"
99

10-
bool ZigbeeEP::_is_bound = false;
11-
bool ZigbeeEP::_allow_multiple_binding = false;
12-
13-
//TODO: is_bound and allow_multiple_binding to make not static
14-
1510
/* Zigbee End Device Class */
1611
ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
1712
_endpoint = endpoint;
@@ -22,6 +17,9 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
2217
_read_model = NULL;
2318
_read_manufacturer = NULL;
2419
_time_status = 0;
20+
_is_bound = false;
21+
_use_manual_binding = false;
22+
_allow_multiple_binding = false;
2523
if (!lock) {
2624
lock = xSemaphoreCreateBinary();
2725
if (lock == NULL) {
@@ -562,6 +560,54 @@ void ZigbeeEP::requestOTAUpdate() {
562560
esp_zb_lock_release();
563561
}
564562

563+
void ZigbeeEP::removeBoundDevice(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
564+
log_d(
565+
"Attempting to remove device with endpoint %d and IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6], ieee_addr[5],
566+
ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
567+
);
568+
569+
for (std::list<zb_device_params_t *>::iterator it = _bound_devices.begin(); it != _bound_devices.end(); ++it) {
570+
if ((*it)->endpoint == endpoint && memcmp((*it)->ieee_addr, ieee_addr, sizeof(esp_zb_ieee_addr_t)) == 0) {
571+
log_d("Found matching device, removing it");
572+
_bound_devices.erase(it);
573+
if (_bound_devices.empty()) {
574+
_is_bound = false;
575+
}
576+
return;
577+
}
578+
}
579+
log_w("No matching device found for removal");
580+
}
581+
582+
void ZigbeeEP::removeBoundDevice(zb_device_params_t *device) {
583+
if (!device) {
584+
log_e("Invalid device parameters provided");
585+
return;
586+
}
587+
588+
log_d(
589+
"Attempting to remove device with endpoint %d, short address 0x%04x, IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", device->endpoint,
590+
device->short_addr, device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2],
591+
device->ieee_addr[1], device->ieee_addr[0]
592+
);
593+
594+
for (std::list<zb_device_params_t *>::iterator it = _bound_devices.begin(); it != _bound_devices.end(); ++it) {
595+
bool endpoint_matches = ((*it)->endpoint == device->endpoint);
596+
bool short_addr_matches = (device->short_addr != 0xFFFF && (*it)->short_addr == device->short_addr);
597+
bool ieee_addr_matches = (memcmp((*it)->ieee_addr, device->ieee_addr, sizeof(esp_zb_ieee_addr_t)) == 0);
598+
599+
if (endpoint_matches && (short_addr_matches || ieee_addr_matches)) {
600+
log_d("Found matching device by %s, removing it", short_addr_matches ? "short address" : "IEEE address");
601+
_bound_devices.erase(it);
602+
if (_bound_devices.empty()) {
603+
_is_bound = false;
604+
}
605+
return;
606+
}
607+
}
608+
log_w("No matching device found for removal");
609+
}
610+
565611
const char *ZigbeeEP::esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status) {
566612
switch (status) {
567613
case ESP_ZB_ZCL_STATUS_SUCCESS: return "Success";

‎libraries/Zigbee/src/ZigbeeEP.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,15 @@ class ZigbeeEP {
6666
return _bound_devices;
6767
}
6868

69-
static bool bound() {
69+
bool bound() {
7070
return _is_bound;
7171
}
72-
static void allowMultipleBinding(bool bind) {
72+
void allowMultipleBinding(bool bind) {
7373
_allow_multiple_binding = bind;
7474
}
75+
void setManualBinding(bool bind) {
76+
_use_manual_binding = bind;
77+
}
7578

7679
// Set Manufacturer name and model
7780
bool setManufacturerAndModel(const char *name, const char *model);
@@ -98,6 +101,9 @@ class ZigbeeEP {
98101
bool epAllowMultipleBinding() {
99102
return _allow_multiple_binding;
100103
}
104+
bool epUseManualBinding() {
105+
return _use_manual_binding;
106+
}
101107

102108
// OTA methods
103109
/**
@@ -138,6 +144,14 @@ class ZigbeeEP {
138144
_is_bound = true;
139145
}
140146

147+
virtual void removeBoundDevice(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
148+
virtual void removeBoundDevice(zb_device_params_t *device);
149+
150+
virtual void clearBoundDevices() {
151+
_bound_devices.clear();
152+
_is_bound = false;
153+
}
154+
141155
void onIdentify(void (*callback)(uint16_t)) {
142156
_on_identify = callback;
143157
}
@@ -157,8 +171,9 @@ class ZigbeeEP {
157171
esp_zb_ha_standard_devices_t _device_id;
158172
esp_zb_endpoint_config_t _ep_config;
159173
esp_zb_cluster_list_t *_cluster_list;
160-
static bool _is_bound;
161-
static bool _allow_multiple_binding;
174+
bool _is_bound;
175+
bool _allow_multiple_binding;
176+
bool _use_manual_binding;
162177
std::list<zb_device_params_t *> _bound_devices;
163178
SemaphoreHandle_t lock;
164179
zb_power_source_t _power_source;

‎libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ ZigbeeColorDimmerSwitch *ZigbeeColorDimmerSwitch::_instance = nullptr;
66

77
ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) {
88
_device_id = ESP_ZB_HA_COLOR_DIMMER_SWITCH_DEVICE_ID;
9-
_instance = this; // Set the static pointer to this instance
9+
_instance = this; // Set the static pointer to this instance
10+
_device = nullptr; // Initialize light pointer to null
1011

1112
esp_zb_color_dimmable_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_COLOR_DIMMABLE_SWITCH_CONFIG();
1213
_cluster_list = esp_zb_color_dimmable_switch_clusters_create(&switch_cfg);
@@ -17,20 +18,39 @@ ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(en
1718
}
1819

1920
void ZigbeeColorDimmerSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
21+
ZigbeeColorDimmerSwitch *instance = static_cast<ZigbeeColorDimmerSwitch *>(user_ctx);
2022
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
2123
log_i("Bound successfully!");
22-
if (user_ctx) {
23-
zb_device_params_t *light = (zb_device_params_t *)user_ctx;
24+
if (instance->_device) {
25+
zb_device_params_t *light = (zb_device_params_t *)instance->_device;
2426
log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint);
25-
_instance->_bound_devices.push_back(light);
27+
log_d("Light bound to a switch on EP %d", instance->_endpoint);
28+
instance->_bound_devices.push_back(light);
2629
}
27-
_is_bound = true;
30+
instance->_is_bound = true;
2831
} else {
29-
log_e("Binding failed!");
32+
instance->_device = nullptr;
33+
}
34+
}
35+
36+
void ZigbeeColorDimmerSwitch::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
37+
ZigbeeColorDimmerSwitch *instance = static_cast<ZigbeeColorDimmerSwitch *>(user_ctx);
38+
if (instance) {
39+
log_d("bindCbWrapper on EP %d", instance->_endpoint);
40+
instance->bindCb(zdo_status, user_ctx);
41+
}
42+
}
43+
44+
void ZigbeeColorDimmerSwitch::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
45+
ZigbeeColorDimmerSwitch *instance = static_cast<ZigbeeColorDimmerSwitch *>(user_ctx);
46+
if (instance) {
47+
log_d("findCbWrapper on EP %d", instance->_endpoint);
48+
instance->findCb(zdo_status, addr, endpoint, user_ctx);
3049
}
3150
}
3251

3352
void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
53+
ZigbeeColorDimmerSwitch *instance = static_cast<ZigbeeColorDimmerSwitch *>(user_ctx);
3454
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
3555
log_d("Found light endpoint");
3656
esp_zb_zdo_bind_req_param_t bind_req;
@@ -39,22 +59,23 @@ void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t ad
3959
light->short_addr = addr;
4060
esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr);
4161
esp_zb_get_long_address(bind_req.src_address);
42-
bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint;
62+
bind_req.src_endp = instance->_endpoint;
4363
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;
4464
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
4565
memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t));
4666
bind_req.dst_endp = endpoint;
4767
bind_req.req_dst_addr = esp_zb_get_short_address();
68+
instance->_device = light;
4869
log_v("Try to bind on/off control of dimmable light");
49-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL);
70+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, NULL);
5071
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL;
5172
log_v("Try to bind level control of dimmable light");
52-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL);
73+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, NULL);
5374
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL;
5475
log_v("Try to bind color control of dimmable light");
55-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light);
76+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeColorDimmerSwitch::bindCbWrapper, this);
5677
} else {
57-
log_v("No color dimmable light endpoint found");
78+
log_d("No color dimmable light endpoint found");
5879
}
5980
}
6081

@@ -70,7 +91,7 @@ void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cm
7091
.num_out_clusters = 3,
7192
.cluster_list = cluster_list,
7293
};
73-
esp_zb_zdo_match_cluster(&color_dimmable_light_req, findCb, &_endpoint);
94+
esp_zb_zdo_match_cluster(&color_dimmable_light_req, ZigbeeColorDimmerSwitch::findCbWrapper, this);
7495
}
7596

7697
// Methods to control the light

‎libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ class ZigbeeColorDimmerSwitch : public ZigbeeEP {
4747
private:
4848
// save instance of the class in order to use it in static functions
4949
static ZigbeeColorDimmerSwitch *_instance;
50+
zb_device_params_t *_device;
5051

5152
void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req);
52-
static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
53-
static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
53+
void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
54+
void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
55+
static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx);
56+
static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
5457

5558
void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y);
5659
};

‎libraries/Zigbee/src/ep/ZigbeeSwitch.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ZigbeeSwitch *ZigbeeSwitch::_instance = nullptr;
77
ZigbeeSwitch::ZigbeeSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) {
88
_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID;
99
_instance = this; // Set the static pointer to this instance
10+
_device = nullptr;
1011

1112
esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG();
1213
_cluster_list = esp_zb_on_off_switch_clusters_create(&switch_cfg);
@@ -15,34 +16,62 @@ ZigbeeSwitch::ZigbeeSwitch(uint8_t endpoint) : ZigbeeEP(endpoint) {
1516
}
1617

1718
void ZigbeeSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
19+
ZigbeeSwitch *instance = static_cast<ZigbeeSwitch *>(user_ctx);
1820
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
1921
log_i("Bound successfully!");
20-
if (user_ctx) {
21-
zb_device_params_t *light = (zb_device_params_t *)user_ctx;
22+
if (instance->_device) {
23+
zb_device_params_t *light = (zb_device_params_t *)instance->_device;
2224
log_i("The light originating from address(0x%x) on endpoint(%d)", light->short_addr, light->endpoint);
23-
_instance->_bound_devices.push_back(light);
25+
log_d("Light bound to a switch on EP %d", instance->_endpoint);
26+
instance->_bound_devices.push_back(light);
2427
}
25-
_is_bound = true;
28+
instance->_is_bound = true;
29+
} else {
30+
instance->_device = nullptr;
31+
}
32+
}
33+
34+
void ZigbeeSwitch::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
35+
ZigbeeSwitch *instance = static_cast<ZigbeeSwitch *>(user_ctx);
36+
if (instance) {
37+
log_d("bindCbWrapper on EP %d", instance->_endpoint);
38+
instance->bindCb(zdo_status, user_ctx);
39+
}
40+
}
41+
42+
// Static wrapper for findCb
43+
void ZigbeeSwitch::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
44+
ZigbeeSwitch *instance = static_cast<ZigbeeSwitch *>(user_ctx);
45+
if (instance) {
46+
log_d("findCbWrapper on EP %d", instance->_endpoint);
47+
instance->findCb(zdo_status, addr, endpoint, user_ctx);
2648
}
2749
}
2850

2951
void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
52+
ZigbeeSwitch *instance = static_cast<ZigbeeSwitch *>(user_ctx);
3053
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
3154
log_d("Found light endpoint");
3255
esp_zb_zdo_bind_req_param_t bind_req;
3356
zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t));
3457
light->endpoint = endpoint;
3558
light->short_addr = addr;
3659
esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr);
60+
log_d("Light found: short address(0x%x), endpoint(%d)", light->short_addr, light->endpoint);
61+
3762
esp_zb_get_long_address(bind_req.src_address);
38-
bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint;
63+
bind_req.src_endp = instance->_endpoint;
3964
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;
4065
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
4166
memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t));
4267
bind_req.dst_endp = endpoint;
4368
bind_req.req_dst_addr = esp_zb_get_short_address();
44-
log_i("Try to bind On/Off");
45-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)light);
69+
log_v("Try to bind On/Off");
70+
//save light params in the class
71+
instance->_device = light;
72+
73+
log_d("Find callback on EP %d", instance->_endpoint);
74+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeSwitch::bindCbWrapper, this);
4675
} else {
4776
log_d("No light endpoint found");
4877
}
@@ -59,7 +88,7 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
5988
.num_out_clusters = 1,
6089
.cluster_list = cluster_list,
6190
};
62-
esp_zb_zdo_match_cluster(&on_off_req, findCb, &_endpoint);
91+
esp_zb_zdo_match_cluster(&on_off_req, ZigbeeSwitch::findCbWrapper, this);
6392
}
6493

6594
// Methods to control the light

‎libraries/Zigbee/src/ep/ZigbeeSwitch.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ class ZigbeeSwitch : public ZigbeeEP {
3737
private:
3838
// save instance of the class in order to use it in static functions
3939
static ZigbeeSwitch *_instance;
40-
40+
zb_device_params_t *_device;
4141
void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req);
42-
static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
43-
static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
42+
void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
43+
void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
44+
static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
45+
static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx);
4446
};
4547

4648
#endif // CONFIG_ZB_ENABLED

‎libraries/Zigbee/src/ep/ZigbeeThermostat.cpp

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ ZigbeeThermostat *ZigbeeThermostat::_instance = nullptr;
1010

1111
ZigbeeThermostat::ZigbeeThermostat(uint8_t endpoint) : ZigbeeEP(endpoint) {
1212
_device_id = ESP_ZB_HA_THERMOSTAT_DEVICE_ID;
13-
_instance = this; // Set the static pointer to this instance
13+
_instance = this; // Set the static pointer to this instance
14+
_device = nullptr; // Initialize sensor pointer to null
1415

1516
//use custom config to avoid narrowing error -> must be fixed in zigbee-sdk
1617
esp_zb_thermostat_cfg_t thermostat_cfg = ZB_DEFAULT_THERMOSTAT_CONFIG();
@@ -29,21 +30,39 @@ ZigbeeThermostat::ZigbeeThermostat(uint8_t endpoint) : ZigbeeEP(endpoint) {
2930
}
3031

3132
void ZigbeeThermostat::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
33+
ZigbeeThermostat *instance = static_cast<ZigbeeThermostat *>(user_ctx);
3234
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
33-
if (user_ctx) {
34-
zb_device_params_t *sensor = (zb_device_params_t *)user_ctx;
35-
log_i("The temperature sensor originating from address(0x%x) on endpoint(%d)", sensor->short_addr, sensor->endpoint);
36-
_instance->_bound_devices.push_back(sensor);
37-
} else {
38-
log_v("Local binding success");
35+
log_i("Bound successfully!");
36+
if (instance->_device) {
37+
zb_device_params_t *sensor = (zb_device_params_t *)instance->_device;
38+
log_i("The sensor originating from address(0x%x) on endpoint(%d)", sensor->short_addr, sensor->endpoint);
39+
log_d("Sensor bound to thermostat on EP %d", instance->_endpoint);
40+
instance->_bound_devices.push_back(sensor);
3941
}
40-
_is_bound = true;
42+
instance->_is_bound = true;
4143
} else {
42-
log_e("Binding failed!");
44+
instance->_device = nullptr;
45+
}
46+
}
47+
48+
void ZigbeeThermostat::bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
49+
ZigbeeThermostat *instance = static_cast<ZigbeeThermostat *>(user_ctx);
50+
if (instance) {
51+
log_d("bindCbWrapper on EP %d", instance->_endpoint);
52+
instance->bindCb(zdo_status, user_ctx);
53+
}
54+
}
55+
56+
void ZigbeeThermostat::findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
57+
ZigbeeThermostat *instance = static_cast<ZigbeeThermostat *>(user_ctx);
58+
if (instance) {
59+
log_d("findCbWrapper on EP %d", instance->_endpoint);
60+
instance->findCb(zdo_status, addr, endpoint, user_ctx);
4361
}
4462
}
4563

4664
void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
65+
ZigbeeThermostat *instance = static_cast<ZigbeeThermostat *>(user_ctx);
4766
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
4867
log_i("Found temperature sensor");
4968
esp_zb_zdo_bind_req_param_t bind_req;
@@ -56,37 +75,34 @@ void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uin
5675

5776
/* 1. Send binding request to the sensor */
5877
bind_req.req_dst_addr = addr;
59-
log_d("Request temperature sensor to bind us");
60-
61-
/* populate the src information of the binding */
6278
memcpy(bind_req.src_address, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t));
6379
bind_req.src_endp = endpoint;
6480
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
65-
log_d("Bind temperature sensor");
66-
67-
/* populate the dst information of the binding */
6881
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
6982
esp_zb_get_long_address(bind_req.dst_address_u.addr_long);
70-
bind_req.dst_endp = *((uint8_t *)user_ctx); //_endpoint;
83+
bind_req.dst_endp = instance->_endpoint;
7184

7285
log_i("Request temperature sensor to bind us");
73-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, NULL);
86+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeThermostat::bindCbWrapper, NULL);
7487

7588
/* 2. Send binding request to self */
7689
bind_req.req_dst_addr = esp_zb_get_short_address();
7790

7891
/* populate the src information of the binding */
7992
esp_zb_get_long_address(bind_req.src_address);
80-
bind_req.src_endp = *((uint8_t *)user_ctx); //_endpoint;
93+
bind_req.src_endp = instance->_endpoint;
8194
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
82-
83-
/* populate the dst information of the binding */
8495
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
8596
memcpy(bind_req.dst_address_u.addr_long, sensor->ieee_addr, sizeof(esp_zb_ieee_addr_t));
8697
bind_req.dst_endp = endpoint;
98+
log_i("Try to bind Temperature Measurement");
99+
//save sensor params in the class
100+
instance->_device = sensor;
87101

88-
log_i("Bind temperature sensor");
89-
esp_zb_zdo_device_bind_req(&bind_req, bindCb, (void *)sensor);
102+
log_d("Find callback on EP %d", instance->_endpoint);
103+
esp_zb_zdo_device_bind_req(&bind_req, ZigbeeThermostat::bindCbWrapper, this);
104+
} else {
105+
log_d("No temperature sensor endpoint found");
90106
}
91107
}
92108

@@ -96,7 +112,7 @@ void ZigbeeThermostat::findEndpoint(esp_zb_zdo_match_desc_req_param_t *param) {
96112
param->num_in_clusters = 1;
97113
param->num_out_clusters = 0;
98114
param->cluster_list = cluster_list;
99-
esp_zb_zdo_match_cluster(param, findCb, &_endpoint);
115+
esp_zb_zdo_match_cluster(param, ZigbeeThermostat::findCbWrapper, this);
100116
}
101117

102118
void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {

‎libraries/Zigbee/src/ep/ZigbeeThermostat.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class ZigbeeThermostat : public ZigbeeEP {
4848
private:
4949
// save instance of the class in order to use it in static functions
5050
static ZigbeeThermostat *_instance;
51+
zb_device_params_t *_device;
5152

5253
void (*_on_temp_recieve)(float);
5354
void (*_on_config_recieve)(float, float, float);
@@ -56,8 +57,10 @@ class ZigbeeThermostat : public ZigbeeEP {
5657
float _tolerance;
5758

5859
void findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req);
59-
static void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
60-
static void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
60+
void bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
61+
void findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
62+
static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx);
63+
static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
6164

6265
void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override;
6366
};

0 commit comments

Comments
 (0)
Please sign in to comment.