Skip to content

Commit a02ab68

Browse files
committed
feat(zigbee): Add SmartButton endpoint
1 parent 3c3ff48 commit a02ab68

File tree

7 files changed

+313
-0
lines changed

7 files changed

+313
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS
284284
libraries/Zigbee/src/ep/ZigbeePressureSensor.cpp
285285
libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp
286286
libraries/Zigbee/src/ep/ZigbeeCarbonDioxideSensor.cpp
287+
libraries/Zigbee/src/ep/ZigbeeSmartButton.cpp
287288
)
288289

289290
set(ARDUINO_LIBRARY_BLE_SRCS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Arduino-ESP32 Zigbee On/Off Light Switch Example
2+
3+
This example shows how to configure Zigbee Coordinator and use it as a Home Automation (HA) on/off light switch.
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 end device (loaded with Zigbee_On_Off_Light example).
15+
* A USB cable for power supply and programming.
16+
* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee coordinator and upload the Zigbee_On_Off_Switch example.
17+
18+
### Configure the Project
19+
20+
Set the Button Switch GPIO by changing the `GPIO_INPUT_IO_TOGGLE_SWITCH` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2).
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+
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.
35+
You can do the following:
36+
37+
* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`.
38+
* In the `Zigbee_On_Off_Light` example sketch call `Zigbee.factoryReset();`.
39+
40+
By default, the coordinator network is closed after rebooting or flashing new firmware.
41+
To open the network you have 2 options:
42+
43+
* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`.
44+
* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join.
45+
46+
***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
47+
48+
* **LED not blinking:** Check the wiring connection and the IO selection.
49+
* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed.
50+
* **COM port not detected:** Check the USB cable and the USB to Serial driver installation.
51+
52+
If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute).
53+
54+
## Contribute
55+
56+
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
57+
58+
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!
59+
60+
Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else.
61+
62+
## Resources
63+
64+
* Official ESP32 Forum: [Link](https://esp32.com)
65+
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
66+
* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
67+
* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf)
68+
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
// Copyright 2024 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 light switch.
17+
*
18+
* The example demonstrates how to use Zigbee library to control a light bulb.
19+
* The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator (Switch).
20+
* Button switch and Zigbee runs in separate tasks.
21+
*
22+
* Proper Zigbee mode must be selected in Tools->Zigbee mode
23+
* and also the correct partition scheme must be selected in Tools->Partition Scheme.
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_ED
31+
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
32+
#endif
33+
34+
#include "Zigbee.h"
35+
36+
/* Zigbee Smart button () configuration */
37+
#define SWITCH_1_ENDPOINT_NUMBER 5 // SINGLE PRESS
38+
#define SWITCH_2_ENDPOINT_NUMBER 6 // DOUBLE PRESS
39+
#define SWITCH_3_ENDPOINT_NUMBER 7 // LONG PRESS
40+
41+
uint8_t button = BOOT_PIN;
42+
43+
// Timing thresholds (in milliseconds)
44+
const uint16_t debounceTime = 100; // Debounce time
45+
const uint16_t doublePressTime = 200; // Max time between double presses
46+
const uint16_t longPressTime = 1000; // Time to detect a long press
47+
const uint16_t rebootPressTime = 5000; // Time to detect a long press for reboot
48+
49+
// Variables to track button state
50+
int buttonState = HIGH; // Current state of the button (HIGH means not pressed)
51+
int lastButtonState = HIGH; // Previous state of the button
52+
53+
// Timing variables
54+
unsigned long lastDebounceTime = 0; // Last time the button state changed
55+
unsigned long firstPressTime = 0; // Time of the first press in a sequence
56+
unsigned long buttonPressStart = 0; // Time when the button was first pressed down
57+
58+
// Flags
59+
bool singlePressDetected = false;
60+
bool doublePressDetected = false;
61+
bool longPressDetected = false;
62+
bool rebootPressDetected = false;
63+
bool longPressHandled = false;
64+
bool doublePressHandled = false;
65+
66+
ZigbeeSmartButton zbSmartButton1 = ZigbeeSmartButton(SWITCH_1_ENDPOINT_NUMBER);
67+
ZigbeeSmartButton zbSmartButton2 = ZigbeeSmartButton(SWITCH_2_ENDPOINT_NUMBER);
68+
ZigbeeSmartButton zbSmartButton3 = ZigbeeSmartButton(SWITCH_3_ENDPOINT_NUMBER);
69+
70+
/********************* Arduino functions **************************/
71+
void setup() {
72+
Serial.begin(115200);
73+
74+
// Configure button switch
75+
pinMode(button, INPUT_PULLUP);
76+
77+
//Optional: set Zigbee device name and model
78+
zbSmartButton1.setManufacturerAndModel("Espressif", "ZigbeeSmartButton");
79+
zbSmartButton2.setManufacturerAndModel("Espressif", "ZigbeeSmartButton");
80+
zbSmartButton3.setManufacturerAndModel("Espressif", "ZigbeeSmartButton");
81+
82+
//Add endpoints to Zigbee Core
83+
Zigbee.addEndpoint(&zbSmartButton1);
84+
Zigbee.addEndpoint(&zbSmartButton2);
85+
Zigbee.addEndpoint(&zbSmartButton3);
86+
87+
// // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
88+
// if (!Zigbee.begin()) {
89+
// Serial.println("Zigbee failed to start!");
90+
// Serial.println("Short press the button to reboot, long press to factory reset Zigbee.");
91+
// // on button press reboot, on long press factory reset
92+
// while(true){
93+
// if (digitalRead(button) == LOW) {
94+
// delay(100);
95+
// int startTime = millis();
96+
// while (digitalRead(button) == LOW) {
97+
// delay(50);
98+
// if ((millis() - startTime) > 3000) {
99+
// Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
100+
// delay(1000);
101+
// Zigbee.factoryReset();
102+
// }
103+
// }
104+
// ESP.restart();
105+
// }
106+
// delay(1);
107+
// }
108+
// }
109+
// Serial.println("Connecting to network");
110+
// while (!Zigbee.connected()) {
111+
// Serial.print(".");
112+
// delay(100);
113+
// }
114+
// Serial.println();
115+
}
116+
117+
void loop() {
118+
// Read the button state
119+
int reading = digitalRead(button);
120+
121+
// Debounce handling
122+
if (reading != lastButtonState) {
123+
lastDebounceTime = millis();
124+
}
125+
126+
if ((millis() - lastDebounceTime) > debounceTime) {
127+
// If the state has stabilized, update button state
128+
if (reading != buttonState) {
129+
buttonState = reading;
130+
131+
// Detect press events
132+
if (buttonState == LOW) {
133+
buttonPressStart = millis();
134+
135+
if (millis() - firstPressTime <= doublePressTime && firstPressTime != 0) {
136+
doublePressDetected = true;
137+
firstPressTime = 0; // Reset for the next sequence
138+
} else {
139+
firstPressTime = millis();
140+
}
141+
} else {
142+
// Button released
143+
unsigned long pressDuration = millis() - buttonPressStart;
144+
145+
if (!longPressHandled && pressDuration >= rebootPressTime) {
146+
rebootPressDetected = true;
147+
} else if (!longPressHandled && pressDuration >= longPressTime) {
148+
longPressDetected = true;
149+
} else if (!doublePressHandled && !doublePressDetected && pressDuration < longPressTime) {
150+
singlePressDetected = true;
151+
}
152+
153+
longPressHandled = false; // Reset for next press
154+
155+
// // If button is pressed again in a short time, it's a double press so reset the single press flag
156+
// if (singlePressDetected){
157+
// // wait for the double press time window
158+
159+
// }
160+
}
161+
}
162+
}
163+
164+
// Handle events
165+
if (singlePressDetected && !doublePressDetected) {
166+
Serial.println("Single press detected");
167+
singlePressDetected = false;
168+
// zbSmartButton1.toggle();
169+
}
170+
171+
if (doublePressDetected) {
172+
Serial.println("Double press detected");
173+
doublePressDetected = false;
174+
doublePressHandled = true;
175+
// zbSmartButton2.toggle();
176+
}
177+
178+
if (longPressDetected) {
179+
Serial.println("Long press detected");
180+
longPressDetected = false;
181+
longPressHandled = true;
182+
// zbSmartButton3.toggle();
183+
}
184+
185+
if (rebootPressDetected) {
186+
Serial.println("Reboot press detected. Rebooting...");
187+
rebootPressDetected = false;
188+
longPressHandled = true;
189+
// Zigbee.factoryReset();
190+
}
191+
192+
lastButtonState = reading;
193+
}
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/Zigbee.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
#include "ep/ZigbeeFlowSensor.h"
1818
#include "ep/ZigbeeOccupancySensor.h"
1919
#include "ep/ZigbeeCarbonDioxideSensor.h"
20+
#include "ep/ZigbeeSmartButton.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "ZigbeeSmartButton.h"
2+
#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
3+
4+
ZigbeeSmartButton::ZigbeeSmartButton(uint8_t endpoint) : ZigbeeEP(endpoint) {
5+
_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID;
6+
7+
esp_zb_on_off_switch_cfg_t switch_cfg = ESP_ZB_DEFAULT_ON_OFF_SWITCH_CONFIG();
8+
_cluster_list = esp_zb_on_off_switch_clusters_create(&switch_cfg);
9+
10+
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_ON_OFF_SWITCH_DEVICE_ID, .app_device_version = 0};
11+
}
12+
13+
void ZigbeeSmartButton::toggle() {
14+
esp_zb_zcl_on_off_cmd_t cmd_req;
15+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
16+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
17+
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
18+
log_v("Sending 'Smart button (ep: %d) toggle' command", _endpoint);
19+
esp_zb_lock_acquire(portMAX_DELAY);
20+
esp_zb_zcl_on_off_cmd_req(&cmd_req);
21+
esp_zb_lock_release();
22+
}
23+
24+
#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Class of Zigbee On/Off Switch endpoint inherited from common EP class */
2+
3+
#pragma once
4+
5+
#include "soc/soc_caps.h"
6+
#include "sdkconfig.h"
7+
#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
8+
9+
#include "ZigbeeEP.h"
10+
#include "ha/esp_zigbee_ha_standard.h"
11+
12+
class ZigbeeSmartButton : public ZigbeeEP {
13+
public:
14+
ZigbeeSmartButton(uint8_t endpoint);
15+
~ZigbeeSmartButton();
16+
17+
void toggle();
18+
};
19+
20+
#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED

0 commit comments

Comments
 (0)