Skip to content

Commit 3078306

Browse files
committed
Dev update: implement on/off light and switch methods
Implemented basic function calls of switch commands to on/off light: lightToggle, lightOn, lightOff, ... Implemented virtual methods for on/off light that have to be override in user code: setOnOff, sceneControl, setOnOffTime, setOffWaitTime APIs can be changed, still early development.
1 parent 8ce22e1 commit 3078306

File tree

7 files changed

+157
-38
lines changed

7 files changed

+157
-38
lines changed

libraries/Zigbee/examples/Zigbee_Light_Bulb/Zigbee_Light_Bulb.ino

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023 Espressif Systems (Shanghai) PTE LTD
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@
2222
* and also the correct partition scheme must be selected in Tools->Partition Scheme.
2323
*
2424
* Please check the README.md for instructions and more detailed description.
25+
*
26+
* Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
2527
*/
2628

2729
#ifndef ZIGBEE_MODE_ED
@@ -45,7 +47,7 @@ public:
4547
MyZigbeeLight(uint8_t endpoint) : ZigbeeLight(endpoint) {}
4648

4749
// Override the set_on_off function
48-
void set_on_off(bool value) override {
50+
void setOnOff(bool value) override {
4951
log_v("Overwritten method, set on/off: %d", value);
5052
neopixelWrite(LED_PIN, 255 * value, 255 * value, 255 * value); // Toggle light
5153
}

libraries/Zigbee/examples/Zigbee_Light_Switch/Zigbee_Light_Switch.ino

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// Copyright 2023 Espressif Systems (Shanghai) PTE LTD
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at
6-
6+
//
77
// http://www.apache.org/licenses/LICENSE-2.0
88
//
99
// Unless required by applicable law or agreed to in writing, software
@@ -16,13 +16,15 @@
1616
* @brief This example demonstrates simple Zigbee light switch.
1717
*
1818
* The example demonstrates how to use ESP Zigbee stack to control a light bulb.
19-
* The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator.
19+
* The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator (Switch).
2020
* Button switch and Zigbee runs in separate tasks.
2121
*
2222
* Proper Zigbee mode must be selected in Tools->Zigbee mode
2323
* and also the correct partition scheme must be selected in Tools->Partition Scheme.
2424
*
2525
* 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/)
2628
*/
2729

2830
#ifndef ZIGBEE_MODE_ZCZR
@@ -68,16 +70,14 @@ typedef enum {
6870

6971
static switch_func_pair_t button_func_pair[] = {{GPIO_INPUT_IO_TOGGLE_SWITCH, SWITCH_ONOFF_TOGGLE_CONTROL}};
7072

73+
/* Zigbee switch */
74+
ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);
75+
7176
/********************* Zigbee functions **************************/
7277
static void esp_zb_buttons_handler(switch_func_pair_t *button_func_pair) {
7378
if (button_func_pair->func == SWITCH_ONOFF_TOGGLE_CONTROL) {
74-
/* implemented light switch toggle functionality */
75-
esp_zb_zcl_on_off_cmd_t cmd_req;
76-
cmd_req.zcl_basic_cmd.src_endpoint = SWITCH_ENDPOINT_NUMBER;
77-
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
78-
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
79-
log_i("Send 'on_off toggle' command");
80-
esp_zb_zcl_on_off_cmd_req(&cmd_req);
79+
// Send toggle command to the light
80+
zbSwitch.lightToggle();
8181
}
8282
}
8383

@@ -98,8 +98,6 @@ static void switch_gpios_intr_enabled(bool enabled) {
9898
}
9999
}
100100

101-
ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);
102-
103101
/********************* Arduino functions **************************/
104102
void setup() {
105103

libraries/Zigbee/src/Zigbee_ep.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class Zigbee_EP {
1414
Zigbee_EP(uint8_t endpoint = 10);
1515
~Zigbee_EP();
1616

17-
virtual void find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) = 0;
17+
// Find endpoint may be implemented by EPs
18+
virtual void find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {};
1819

1920
static uint8_t _endpoint;
2021
esp_zb_ha_standard_devices_t _device_id; //type of device

libraries/Zigbee/src/ep/ep_on_off_light.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,51 @@ ZigbeeLight::ZigbeeLight(uint8_t endpoint) : Zigbee_EP(endpoint) {
1414
};
1515
}
1616

17-
void ZigbeeLight::find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
18-
//NOTE: Light is looking for switch?
19-
return;
20-
}
21-
2217
//set attribude method -> methon overriden in child class
2318
void ZigbeeLight::attribute_set(const esp_zb_zcl_set_attr_value_message_t *message) {
2419
//check the data and call right method
2520
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
26-
bool light_state = 0;
2721
if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
28-
light_state = message->attribute.data.value ? *(bool *)message->attribute.data.value : light_state;
29-
set_on_off(light_state);
22+
setOnOff(*(bool *)message->attribute.data.value);
23+
}
24+
else if(message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_GLOBAL_SCENE_CONTROL && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
25+
sceneControl(*(bool *)message->attribute.data.value);
26+
}
27+
else if(message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_TIME && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
28+
setOnOffTime(*(uint16_t *)message->attribute.data.value);
29+
}
30+
else if(message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_OFF_WAIT_TIME && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
31+
setOffWaitTime(*(uint16_t *)message->attribute.data.value);
32+
}
33+
// else if(message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_START_UP_ON_OFF && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
34+
// //TODO: more info needed, not implemented for now
35+
// }
36+
else {
37+
log_w("Recieved message ignored. Attribute ID: %d not supported for On/Off Light", message->attribute.id);
3038
}
3139
}
32-
// if (message->attr_id == ESP_ZB_ON_OFF_LIGHT_ATTR_ON_OFF) {
33-
// //call method to set on/off
34-
// set_on_off(message->attribute.data[0]);
35-
// }
36-
// else if (message->attr_id == ESP_ZB_ON_OFF_LIGHT_ATTR_LEVEL) {
37-
// //call method to set level
38-
// }
3940
else {
40-
//unknown attribute
41+
log_w("Recieved message ignored. Cluster ID: %d not supported for On/Off Light", message->info.cluster);
4142
}
4243
}
4344

4445
//default method to set on/off
45-
void ZigbeeLight::set_on_off(bool value) {
46+
void ZigbeeLight::setOnOff(bool value) {
4647
//set on/off
4748
log_v("Function not overwritten, set on/off: %d", value);
48-
}
49+
}
50+
51+
void ZigbeeLight::sceneControl(bool value) {
52+
//set scene control
53+
log_v("Function not overwritten, set scene control: %d", value);
54+
}
55+
56+
void ZigbeeLight::setOnOffTime(uint16_t value) {
57+
//set on/off time
58+
log_v("Function not overwritten, set on/off time: %d", value);
59+
}
60+
61+
void ZigbeeLight::setOffWaitTime(uint16_t value) {
62+
//set off wait time
63+
log_v("Function not overwritten, set off wait time: %d", value);
64+
}

libraries/Zigbee/src/ep/ep_on_off_light.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ class ZigbeeLight : public Zigbee_EP {
1111
~ZigbeeLight();
1212

1313
// methods to be implemented by the user by overwritting them
14-
virtual void set_on_off(bool value);
14+
virtual void setOnOff(bool value);
15+
virtual void sceneControl(bool value);
16+
virtual void setOnOffTime(uint16_t value);
17+
virtual void setOffWaitTime(uint16_t value);
1518

1619
private:
17-
void find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req);
18-
1920
void attribute_set(const esp_zb_zcl_set_attr_value_message_t *message) override;
2021

2122
};

libraries/Zigbee/src/ep/ep_on_off_switch.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,84 @@ void ZigbeeSwitch::find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
6969

7070
esp_zb_zdo_match_cluster(&on_off_req, find_cb, NULL);
7171
}
72+
73+
// Call to control the light
74+
void ZigbeeSwitch::lightToggle() {
75+
if (_is_bound) {
76+
esp_zb_zcl_on_off_cmd_t cmd_req;
77+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
78+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
79+
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
80+
log_i("Sending 'light toggle' command");
81+
esp_zb_zcl_on_off_cmd_req(&cmd_req);
82+
} else {
83+
log_e("Light not bound");
84+
}
85+
}
86+
87+
void ZigbeeSwitch::lightOn() {
88+
if (_is_bound) {
89+
esp_zb_zcl_on_off_cmd_t cmd_req;
90+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
91+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
92+
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
93+
log_i("Sending 'light on' command");
94+
esp_zb_zcl_on_off_cmd_req(&cmd_req);
95+
} else {
96+
log_e("Light not bound");
97+
}
98+
}
99+
100+
void ZigbeeSwitch::lightOff() {
101+
if (_is_bound) {
102+
esp_zb_zcl_on_off_cmd_t cmd_req;
103+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
104+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
105+
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
106+
log_i("Sending 'light off' command");
107+
esp_zb_zcl_on_off_cmd_req(&cmd_req);
108+
} else {
109+
log_e("Light not bound");
110+
}
111+
}
112+
113+
void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) {
114+
if (_is_bound) {
115+
esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req;
116+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
117+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
118+
cmd_req.effect_id = effect_id;
119+
cmd_req.effect_variant = effect_variant;
120+
log_i("Sending 'light off with effect' command");
121+
esp_zb_zcl_on_off_off_with_effect_cmd_req(&cmd_req);
122+
} else {
123+
log_e("Light not bound");
124+
}
125+
}
126+
127+
void ZigbeeSwitch::lightOnWithSceneRecall() {
128+
if (_is_bound) {
129+
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req;
130+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
131+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
132+
log_i("Sending 'light on with scene recall' command");
133+
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_req(&cmd_req);
134+
} else {
135+
log_e("Light not bound");
136+
}
137+
}
138+
void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) {
139+
if (_is_bound) {
140+
esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req;
141+
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
142+
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
143+
cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API
144+
cmd_req.on_time = time_on;
145+
cmd_req.off_wait_time = time_off;
146+
log_i("Sending 'light on with time off' command");
147+
esp_zb_zcl_on_off_on_with_timed_off_cmd_req(&cmd_req);
148+
} else {
149+
log_e("Light not bound");
150+
}
151+
}
152+

libraries/Zigbee/src/ep/ep_on_off_switch.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Class of Zigbee On/Off Light endpoint inherited from common EP class */
1+
/* Class of Zigbee On/Off Switch endpoint inherited from common EP class */
22

33
#pragma once
44

@@ -10,10 +10,30 @@ class ZigbeeSwitch : public Zigbee_EP {
1010
ZigbeeSwitch(uint8_t endpoint);
1111
~ZigbeeSwitch();
1212

13+
// methods to control the on/off light
14+
void lightToggle();
15+
void lightOn();
16+
void lightOff();
17+
void lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant);
18+
void lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off);
19+
void lightOnWithSceneRecall();
20+
21+
private:
1322
void find_endpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req);
1423
static void bind_cb(esp_zb_zdp_status_t zdo_status, void *user_ctx);
1524
static void find_cb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
1625

1726
static uint8_t get_endpoint() { return _endpoint; }
1827

19-
};
28+
};
29+
30+
//NOTE:
31+
/* ON/OFF switch commands for light control */
32+
// typedef enum {
33+
// ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID = 0x00, /*!< "Turn off" command. */
34+
// ESP_ZB_ZCL_CMD_ON_OFF_ON_ID = 0x01, /*!< "Turn on" command. */
35+
// ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID = 0x02, /*!< "Toggle state" command. */
36+
// ESP_ZB_ZCL_CMD_ON_OFF_OFF_WITH_EFFECT_ID = 0x40, /*!< "Off with effect" command. */
37+
// ESP_ZB_ZCL_CMD_ON_OFF_ON_WITH_RECALL_GLOBAL_SCENE_ID = 0x41, /*!< "On with recall global scene" command. */
38+
// ESP_ZB_ZCL_CMD_ON_OFF_ON_WITH_TIMED_OFF_ID = 0x42, /*!< "On with timed off" command. */
39+
// } esp_zb_zcl_on_off_cmd_id_t;

0 commit comments

Comments
 (0)