Skip to content

Commit fa081b8

Browse files
Add Temperature Dimmable Light
1 parent c32846c commit fa081b8

File tree

3 files changed

+296
-0
lines changed

3 files changed

+296
-0
lines changed

libraries/Zigbee/src/Zigbee.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "ep/ZigbeeSwitch.h"
3030
//// Lights
3131
#include "ep/ZigbeeColorDimmableLight.h"
32+
#include "ep/ZigbeeTemperatureDimmableLight.h"
3233
#include "ep/ZigbeeDimmableLight.h"
3334
#include "ep/ZigbeeLight.h"
3435
//// Controllers
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
2+
// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
#include "ZigbeeTemperatureDimmableLight.h"
17+
#if CONFIG_ZB_ENABLED
18+
19+
ZigbeeTemperatureDimmableLight::ZigbeeTemperatureDimmableLight(uint8_t endpoint) : ZigbeeEP(endpoint) {
20+
_device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID; // Use the correct device ID for color temperature light
21+
22+
zigbee_temperature_dimmable_light_cfg_t light_cfg = ZIGBEE_DEFAULT_TEMPERATURE_DIMMABLE_LIGHT_CONFIG();
23+
_cluster_list = zigbee_temperature_dimmable_light_clusters_create(&light_cfg);
24+
25+
//Add support for Temperature Color Control cluster
26+
esp_zb_attribute_list_t *color_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
27+
uint16_t color_attr = ESP_ZB_ZCL_COLOR_CONTROL_COLOR_TEMPERATURE_DEF_VALUE;
28+
uint16_t min_temp = ESP_ZB_ZCL_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MIN_MIREDS_DEFAULT_VALUE;
29+
uint16_t max_temp = ESP_ZB_ZCL_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MAX_MIREDS_DEFAULT_VALUE;
30+
uint8_t color_mode = ESP_ZB_ZCL_COLOR_CONTROL_COLOR_MODE_DEFAULT_VALUE;
31+
32+
esp_zb_color_control_cluster_add_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMPERATURE_ID, &color_attr);
33+
esp_zb_color_control_cluster_add_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MIN_MIREDS_ID, &min_temp);
34+
esp_zb_color_control_cluster_add_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MAX_MIREDS_ID, &max_temp);
35+
esp_zb_color_control_cluster_add_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_MODE_ID, &color_mode);
36+
37+
_ep_config = {
38+
.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_COLOR_DIMMABLE_LIGHT_DEVICE_ID, .app_device_version = 0
39+
};
40+
41+
// set default values
42+
_current_state = false;
43+
_current_level = 255;
44+
_current_color_temperature = ESP_ZB_ZCL_COLOR_CONTROL_COLOR_TEMPERATURE_DEF_VALUE; // 6500K
45+
}
46+
47+
bool ZigbeeTemperatureDimmableLight::setMinMaxTemperature(uint16_t min_temp, uint16_t max_temp) {
48+
esp_zb_attribute_list_t *color_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
49+
esp_err_t ret = esp_zb_cluster_update_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MIN_MIREDS_ID, &min_temp);
50+
if (ret != ESP_OK) {
51+
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
52+
return false;
53+
}
54+
ret = esp_zb_cluster_update_attr(color_cluster, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMP_PHYSICAL_MAX_MIREDS_ID, &max_temp);
55+
if (ret != ESP_OK) {
56+
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
57+
return false;
58+
}
59+
return true;
60+
}
61+
62+
void ZigbeeTemperatureDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {
63+
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_ON_OFF) {
64+
if (message->attribute.id == ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_BOOL) {
65+
if (_current_state != *(bool *)message->attribute.data.value) {
66+
_current_state = *(bool *)message->attribute.data.value;
67+
lightChanged();
68+
}
69+
return;
70+
} else {
71+
log_w("Received message ignored. Attribute ID: %d not supported for Temperature Dimmable Light", message->attribute.id);
72+
}
73+
} else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL) {
74+
if (message->attribute.id == ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
75+
if (_current_level != *(uint8_t *)message->attribute.data.value) {
76+
_current_level = *(uint8_t *)message->attribute.data.value;
77+
lightChanged();
78+
}
79+
return;
80+
} else {
81+
log_w("Received message ignored. Attribute ID: %d not supported for Temperature Dimmable Light", message->attribute.id);
82+
}
83+
} else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL) {
84+
if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMPERATURE_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
85+
if (_current_color_temperature != *(uint16_t *)message->attribute.data.value) {
86+
_current_color_temperature = *(uint16_t *)message->attribute.data.value;
87+
lightChanged();
88+
}
89+
return;
90+
91+
} else {
92+
log_w("Received message ignored. Attribute ID: %d not supported for Temperature Dimmable Light", message->attribute.id);
93+
}
94+
} else {
95+
log_w("Received message ignored. Cluster ID: %d not supported for Temperature Dimmable Light", message->info.cluster);
96+
}
97+
}
98+
99+
void ZigbeeTemperatureDimmableLight::lightChanged() {
100+
if (_on_light_change) {
101+
_on_light_change(_current_state, _current_level, _current_color_temperature);
102+
}
103+
}
104+
105+
bool ZigbeeTemperatureDimmableLight::setLight(bool state, uint8_t level, uint16_t mireds) {
106+
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
107+
_current_state = state;
108+
_current_level = level;
109+
_current_color_temperature = mireds;
110+
lightChanged();
111+
112+
log_v("Updating light state: %d, level: %d, color temperature: %d", state, level, mireds);
113+
/* Update light clusters */
114+
esp_zb_lock_acquire(portMAX_DELAY);
115+
//set on/off state
116+
ret = esp_zb_zcl_set_attribute_val(
117+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ON_OFF, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID, &_current_state, false
118+
);
119+
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
120+
log_e("Failed to set light state: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));
121+
goto unlock_and_return;
122+
}
123+
//set level
124+
ret = esp_zb_zcl_set_attribute_val(
125+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID, &_current_level, false
126+
);
127+
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
128+
log_e("Failed to set light level: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));
129+
goto unlock_and_return;
130+
}
131+
//set color temperature
132+
ret = esp_zb_zcl_set_attribute_val(
133+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMPERATURE_ID,
134+
&_current_color_temperature, false
135+
);
136+
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
137+
log_e("Failed to set light color temperature: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));
138+
goto unlock_and_return;
139+
}
140+
unlock_and_return:
141+
esp_zb_lock_release();
142+
return ret == ESP_ZB_ZCL_STATUS_SUCCESS;
143+
}
144+
145+
bool ZigbeeTemperatureDimmableLight::setLightState(bool state) {
146+
return setLight(state, _current_level, _current_color_temperature);
147+
}
148+
149+
bool ZigbeeTemperatureDimmableLight::setLightLevel(uint8_t level) {
150+
return setLight(_current_state, level, _current_color_temperature);
151+
}
152+
153+
bool ZigbeeTemperatureDimmableLight::setColorTemperature(uint16_t mireds) {
154+
return setLight(_current_state, _current_level, mireds);
155+
}
156+
157+
esp_zb_cluster_list_t *ZigbeeTemperatureDimmableLight::zigbee_temperature_dimmable_light_clusters_create(zigbee_temperature_dimmable_light_cfg_t *light_cfg) {
158+
esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_basic_cluster_create(&light_cfg->basic_cfg);
159+
esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_identify_cluster_create(&light_cfg->identify_cfg);
160+
esp_zb_attribute_list_t *esp_zb_groups_cluster = esp_zb_groups_cluster_create(&light_cfg->groups_cfg);
161+
esp_zb_attribute_list_t *esp_zb_scenes_cluster = esp_zb_scenes_cluster_create(&light_cfg->scenes_cfg);
162+
esp_zb_attribute_list_t *esp_zb_on_off_cluster = esp_zb_on_off_cluster_create(&light_cfg->on_off_cfg);
163+
esp_zb_attribute_list_t *esp_zb_level_cluster = esp_zb_level_cluster_create(&light_cfg->level_cfg);
164+
esp_zb_attribute_list_t *esp_zb_color_cluster = esp_zb_color_control_cluster_create(&light_cfg->color_cfg);
165+
166+
esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
167+
esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
168+
esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
169+
esp_zb_cluster_list_add_groups_cluster(esp_zb_cluster_list, esp_zb_groups_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
170+
esp_zb_cluster_list_add_scenes_cluster(esp_zb_cluster_list, esp_zb_scenes_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
171+
esp_zb_cluster_list_add_on_off_cluster(esp_zb_cluster_list, esp_zb_on_off_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
172+
esp_zb_cluster_list_add_level_cluster(esp_zb_cluster_list, esp_zb_level_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
173+
esp_zb_cluster_list_add_color_control_cluster(esp_zb_cluster_list, esp_zb_color_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
174+
175+
return esp_zb_cluster_list;
176+
}
177+
178+
#endif // CONFIG_ZB_ENABLED
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
#pragma once
16+
17+
#include "soc/soc_caps.h"
18+
#include "sdkconfig.h"
19+
#if CONFIG_ZB_ENABLED
20+
21+
#include "ZigbeeEP.h"
22+
#include "ha/esp_zigbee_ha_standard.h"
23+
24+
typedef struct zigbee_temperature_dimmable_light_cfg_s {
25+
esp_zb_basic_cluster_cfg_t basic_cfg;
26+
esp_zb_identify_cluster_cfg_t identify_cfg;
27+
esp_zb_groups_cluster_cfg_t groups_cfg;
28+
esp_zb_scenes_cluster_cfg_t scenes_cfg;
29+
esp_zb_on_off_cluster_cfg_t on_off_cfg;
30+
esp_zb_level_cluster_cfg_t level_cfg;
31+
esp_zb_color_cluster_cfg_t color_cfg;
32+
} zigbee_temperature_dimmable_light_cfg_t;
33+
34+
#define ZIGBEE_DEFAULT_TEMPERATURE_DIMMABLE_LIGHT_CONFIG() \
35+
{ \
36+
.basic_cfg = \
37+
{ \
38+
.zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \
39+
.power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \
40+
}, \
41+
.identify_cfg = \
42+
{ \
43+
.identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \
44+
}, \
45+
.groups_cfg = \
46+
{ \
47+
.groups_name_support_id = ESP_ZB_ZCL_GROUPS_NAME_SUPPORT_DEFAULT_VALUE, \
48+
}, \
49+
.scenes_cfg = \
50+
{ \
51+
.scenes_count = ESP_ZB_ZCL_SCENES_SCENE_COUNT_DEFAULT_VALUE, \
52+
.current_scene = ESP_ZB_ZCL_SCENES_CURRENT_SCENE_DEFAULT_VALUE, \
53+
.current_group = ESP_ZB_ZCL_SCENES_CURRENT_GROUP_DEFAULT_VALUE, \
54+
.scene_valid = ESP_ZB_ZCL_SCENES_SCENE_VALID_DEFAULT_VALUE, \
55+
.name_support = ESP_ZB_ZCL_SCENES_NAME_SUPPORT_DEFAULT_VALUE, \
56+
}, \
57+
.on_off_cfg = \
58+
{ \
59+
.on_off = ESP_ZB_ZCL_ON_OFF_ON_OFF_DEFAULT_VALUE, \
60+
}, \
61+
.level_cfg = \
62+
{ \
63+
.current_level = ESP_ZB_ZCL_LEVEL_CONTROL_CURRENT_LEVEL_DEFAULT_VALUE, \
64+
}, \
65+
.color_cfg = { \
66+
.current_x = ESP_ZB_ZCL_COLOR_CONTROL_CURRENT_X_DEF_VALUE, /*!< The current value of the normalized chromaticity value x */ \
67+
.current_y = ESP_ZB_ZCL_COLOR_CONTROL_CURRENT_Y_DEF_VALUE, /*!< The current value of the normalized chromaticity value y */ \
68+
.color_mode = 0x0002, /*!< The mode which attribute determines the color of the device */ \
69+
.options = ESP_ZB_ZCL_COLOR_CONTROL_OPTIONS_DEFAULT_VALUE, /*!< The bitmap determines behavior of some cluster commands */ \
70+
.enhanced_color_mode = \
71+
ESP_ZB_ZCL_COLOR_CONTROL_ENHANCED_COLOR_MODE_DEFAULT_VALUE, /*!< The enhanced-mode which attribute determines the color of the device */ \
72+
.color_capabilities = 0x0010, /*!< Specifying the color capabilities of the device support the color control cluster */ \
73+
}, \
74+
}
75+
76+
class ZigbeeTemperatureDimmableLight : public ZigbeeEP {
77+
public:
78+
ZigbeeTemperatureDimmableLight(uint8_t endpoint);
79+
~ZigbeeTemperatureDimmableLight() {}
80+
81+
bool setMinMaxTemperature(uint16_t min_temp, uint16_t max_temp);
82+
83+
void onLightChange(void (*callback)(bool, uint8_t, uint16_t)) {
84+
_on_light_change = callback;
85+
}
86+
void restoreLight() {
87+
lightChanged();
88+
}
89+
90+
bool setLightState(bool state);
91+
bool setLightLevel(uint8_t level);
92+
bool setColorTemperature(uint16_t mireds);
93+
bool setLight(bool state, uint8_t level, uint16_t mireds);
94+
95+
bool getLightState() {
96+
return _current_state;
97+
}
98+
uint8_t getLightLevel() {
99+
return _current_level;
100+
}
101+
uint16_t getColorTemperature() {
102+
return _current_color_temperature;
103+
}
104+
105+
private:
106+
void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
107+
void lightChanged();
108+
void (*_on_light_change)(bool, uint8_t, uint16_t);
109+
110+
bool _current_state;
111+
uint8_t _current_level;
112+
uint16_t _current_color_temperature;
113+
114+
esp_zb_cluster_list_t *zigbee_temperature_dimmable_light_clusters_create(zigbee_temperature_dimmable_light_cfg_t *light_cfg);
115+
};
116+
117+
#endif // CONFIG_ZB_ENABLED

0 commit comments

Comments
 (0)