Skip to content

Commit a559bdd

Browse files
committed
feat(zigbee): Support HSV color commands
1 parent 5ba4c21 commit a559bdd

File tree

4 files changed

+90
-115
lines changed

4 files changed

+90
-115
lines changed

libraries/Zigbee/src/ZigbeeEP.h

+1-15
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,12 @@
66
#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
77

88
#include <Arduino.h>
9+
#include <ColorFormat.h>
910

1011
/* Useful defines */
1112
#define ZB_CMD_TIMEOUT 10000 // 10 seconds
1213

1314
#define ZB_ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0]))
14-
#define XYZ_TO_RGB(X, Y, Z, r, g, b) \
15-
{ \
16-
r = (float)(3.240479 * (X) - 1.537150 * (Y) - 0.498535 * (Z)); \
17-
g = (float)(-0.969256 * (X) + 1.875992 * (Y) + 0.041556 * (Z)); \
18-
b = (float)(0.055648 * (X) - 0.204043 * (Y) + 1.057311 * (Z)); \
19-
if (r > 1) { \
20-
r = 1; \
21-
} \
22-
if (g > 1) { \
23-
g = 1; \
24-
} \
25-
if (b > 1) { \
26-
b = 1; \
27-
} \
28-
}
2915

3016
#define RGB_TO_XYZ(r, g, b, X, Y, Z) \
3117
{ \

libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.cpp

+65-54
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ ZigbeeColorDimmableLight::ZigbeeColorDimmableLight(uint8_t endpoint) : ZigbeeEP(
1313
//set default values
1414
_current_state = false;
1515
_current_level = 255;
16-
_current_red = 255;
17-
_current_green = 255;
18-
_current_blue = 255;
16+
_current_color = {255, 255, 255};
1917
}
2018

2119
uint16_t ZigbeeColorDimmableLight::getCurrentColorX() {
@@ -32,39 +30,27 @@ uint16_t ZigbeeColorDimmableLight::getCurrentColorY() {
3230
->data_p);
3331
}
3432

35-
void ZigbeeColorDimmableLight::calculateRGB(uint16_t x, uint16_t y, uint8_t &red, uint8_t &green, uint8_t &blue) {
36-
float r, g, b, color_x, color_y;
37-
color_x = (float)x / 65535;
38-
color_y = (float)y / 65535;
39-
40-
float color_X = color_x / color_y;
41-
float color_Z = (1 - color_x - color_y) / color_y;
42-
43-
XYZ_TO_RGB(color_X, 1, color_Z, r, g, b);
44-
45-
red = (uint8_t)(r * (float)255);
46-
green = (uint8_t)(g * (float)255);
47-
blue = (uint8_t)(b * (float)255);
33+
uint16_t ZigbeeColorDimmableLight::getCurrentColorHue() {
34+
return (*(uint16_t *)esp_zb_zcl_get_attribute(
35+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID
36+
)
37+
->data_p);
4838
}
4939

50-
void ZigbeeColorDimmableLight::calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y) {
51-
// Convert RGB to XYZ
52-
float r = (float)red / 255.0f;
53-
float g = (float)green / 255.0f;
54-
float b = (float)blue / 255.0f;
55-
56-
float X, Y, Z;
57-
RGB_TO_XYZ(r, g, b, X, Y, Z);
58-
59-
// Convert XYZ to xy chromaticity coordinates
60-
float color_x = X / (X + Y + Z);
61-
float color_y = Y / (X + Y + Z);
62-
63-
// Convert normalized xy to 16-bit values
64-
x = (uint16_t)(color_x * 65535.0f);
65-
y = (uint16_t)(color_y * 65535.0f);
40+
uint8_t ZigbeeColorDimmableLight::getCurrentColorSaturation() {
41+
return (*(uint16_t *)esp_zb_zcl_get_attribute(
42+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID
43+
)
44+
->data_p);
6645
}
6746

47+
// uint8_t ZigbeeColorDimmableLight::getCurrentColorValue() {
48+
// return (*(uint16_t *)esp_zb_zcl_get_attribute(
49+
// _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMPERATURE_ID
50+
// )
51+
// ->data_p);
52+
// }
53+
6854
//set attribute method -> method overridden in child class
6955
void ZigbeeColorDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {
7056
//check the data and call right method
@@ -94,25 +80,32 @@ void ZigbeeColorDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_me
9480
uint16_t light_color_x = (*(uint16_t *)message->attribute.data.value);
9581
uint16_t light_color_y = getCurrentColorY();
9682
//calculate RGB from XY and call setColor()
97-
uint8_t red, green, blue;
98-
calculateRGB(light_color_x, light_color_y, red, green, blue);
99-
_current_blue = blue;
100-
_current_green = green;
101-
_current_red = red;
83+
_current_color = espXYToRgbColor(255, light_color_x, light_color_y); //TODO: Check if level is correct
10284
lightChanged();
10385
return;
10486

10587
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
10688
uint16_t light_color_x = getCurrentColorX();
10789
uint16_t light_color_y = (*(uint16_t *)message->attribute.data.value);
10890
//calculate RGB from XY and call setColor()
109-
uint8_t red, green, blue;
110-
calculateRGB(light_color_x, light_color_y, red, green, blue);
111-
_current_blue = blue;
112-
_current_green = green;
113-
_current_red = red;
91+
_current_color = espXYToRgbColor(255, light_color_x, light_color_y); //TODO: Check if level is correct
11492
lightChanged();
11593
return;
94+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
95+
uint16_t light_color_hue = (*(uint16_t *)message->attribute.data.value);
96+
_current_color = espHsvToRgbColor(light_color_hue, getCurrentColorSaturation(), 255);
97+
lightChanged();
98+
return;
99+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
100+
uint8_t light_color_saturation = (*(uint8_t *)message->attribute.data.value);
101+
_current_color = espHsvToRgbColor(getCurrentColorHue(), light_color_saturation, 255);
102+
lightChanged();
103+
return;
104+
// } else if (message->attribute.id == ESP_ZB_ZCL_ATTR_COLOR_CONTROL_COLOR_TEMPERATURE_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
105+
// uint16_t light_color_temperature = (*(uint16_t *)message->attribute.data.value);
106+
// _current_color = espHsvToRgbColor(getCurrentColorHue(), getCurrentColorSaturation(), light_color_temperature);
107+
// lightChanged();
108+
// return;
116109
} else {
117110
log_w("Received message ignored. Attribute ID: %d not supported for Color Control", message->attribute.id);
118111
}
@@ -123,20 +116,21 @@ void ZigbeeColorDimmableLight::zbAttributeSet(const esp_zb_zcl_set_attr_value_me
123116

124117
void ZigbeeColorDimmableLight::lightChanged() {
125118
if (_on_light_change) {
126-
_on_light_change(_current_state, _current_red, _current_green, _current_blue, _current_level);
119+
_on_light_change(_current_state, _current_color.r, _current_color.g, _current_color.b, _current_level);
127120
}
128121
}
129122

130123
void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue) {
131124
//Update all attributes
132125
_current_state = state;
133126
_current_level = level;
134-
_current_red = red;
135-
_current_green = green;
136-
_current_blue = blue;
127+
_current_color = {red, green, blue};
137128
lightChanged();
138129

139-
log_v("Updating on/off light state to %d", state);
130+
espXyColor_t xy_color = espRgbColorToXYColor(_current_color);
131+
espHsvColor_t hsv_color = espRgbColorToHsvColor(_current_color);
132+
133+
log_v("Updating light state: %d, level: %d, color: %d, %d, %d", state, level, red, green, blue);
140134
/* Update light clusters */
141135
esp_zb_lock_acquire(portMAX_DELAY);
142136
//set on/off state
@@ -147,28 +141,45 @@ void ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red,
147141
esp_zb_zcl_set_attribute_val(
148142
_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
149143
);
150-
//set color
151-
uint16_t color_x, color_y;
152-
calculateXY(red, green, blue, color_x, color_y);
144+
//set xy color
145+
esp_zb_zcl_set_attribute_val(
146+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID, &xy_color.x, false
147+
);
153148
esp_zb_zcl_set_attribute_val(
154-
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_X_ID, &color_x, false
149+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID, &xy_color.y, false
155150
);
151+
//set hsv color
156152
esp_zb_zcl_set_attribute_val(
157-
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_Y_ID, &color_y, false
153+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID, &hsv_color.h, false
158154
);
155+
esp_zb_zcl_set_attribute_val(
156+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID, &hsv_color.s, false
157+
);
158+
// esp_zb_zcl_set_attribute_val(
159+
// _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_VALUE_ID, &hsv_color.v, false
160+
// );
159161
esp_zb_lock_release();
160162
}
161163

162164
void ZigbeeColorDimmableLight::setLightState(bool state) {
163-
setLight(state, _current_level, _current_red, _current_green, _current_blue);
165+
setLight(state, _current_level, _current_color.r, _current_color.g, _current_color.b);
164166
}
165167

166168
void ZigbeeColorDimmableLight::setLightLevel(uint8_t level) {
167-
setLight(_current_state, level, _current_red, _current_green, _current_blue);
169+
setLight(_current_state, level, _current_color.r, _current_color.g, _current_color.b);
168170
}
169171

170172
void ZigbeeColorDimmableLight::setLightColor(uint8_t red, uint8_t green, uint8_t blue) {
171173
setLight(_current_state, _current_level, red, green, blue);
172174
}
173175

176+
void ZigbeeColorDimmableLight::setLightColor(espRgbColor_t rgb_color) {
177+
setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b);
178+
}
179+
180+
void ZigbeeColorDimmableLight::setLightColor(espHsvColor_t hsv_color) {
181+
espRgbColor_t rgb_color = espHsvColorToRgbColor(hsv_color);
182+
setLight(_current_state, _current_level, rgb_color.r, rgb_color.g, rgb_color.b);
183+
}
184+
174185
#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED

libraries/Zigbee/src/ep/ZigbeeColorDimmableLight.h

+12-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class ZigbeeColorDimmableLight : public ZigbeeEP {
2424
void setLightState(bool state);
2525
void setLightLevel(uint8_t level);
2626
void setLightColor(uint8_t red, uint8_t green, uint8_t blue);
27+
void setLightColor(espRgbColor_t rgb_color);
28+
void setLightColor(espHsvColor_t hsv_color);
2729
void setLight(bool state, uint8_t level, uint8_t red, uint8_t green, uint8_t blue);
2830

2931
bool getLightState() {
@@ -32,33 +34,35 @@ class ZigbeeColorDimmableLight : public ZigbeeEP {
3234
uint8_t getLightLevel() {
3335
return _current_level;
3436
}
37+
espRgbColor_t getLightColor() {
38+
return _current_color;
39+
}
3540
uint8_t getLightRed() {
36-
return _current_red;
41+
return _current_color.r;
3742
}
3843
uint8_t getLightGreen() {
39-
return _current_green;
44+
return _current_color.g;
4045
}
4146
uint8_t getLightBlue() {
42-
return _current_blue;
47+
return _current_color.b;
4348
}
4449

4550
private:
4651
void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
47-
void calculateRGB(uint16_t x, uint16_t y, uint8_t &red, uint8_t &green, uint8_t &blue);
48-
void calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y);
4952

5053
uint16_t getCurrentColorX();
5154
uint16_t getCurrentColorY();
55+
uint16_t getCurrentColorHue();
56+
uint8_t getCurrentColorSaturation();
57+
// uint8_t getCurrentColorValue();
5258

5359
void lightChanged();
5460
//callback function to be called on light change (State, R, G, B, Level)
5561
void (*_on_light_change)(bool, uint8_t, uint8_t, uint8_t, uint8_t);
5662

5763
bool _current_state;
5864
uint8_t _current_level;
59-
uint16_t _current_red;
60-
uint16_t _current_green;
61-
uint16_t _current_blue;
65+
espRgbColor_t _current_color;
6266
};
6367

6468
#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED

libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp

+12-38
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,6 @@ ZigbeeColorDimmerSwitch::ZigbeeColorDimmerSwitch(uint8_t endpoint) : ZigbeeEP(en
1616
};
1717
}
1818

19-
void ZigbeeColorDimmerSwitch::calculateXY(uint8_t red, uint8_t green, uint8_t blue, uint16_t &x, uint16_t &y) {
20-
// Convert RGB to XYZ
21-
float r = (float)red / 255.0f;
22-
float g = (float)green / 255.0f;
23-
float b = (float)blue / 255.0f;
24-
25-
float X, Y, Z;
26-
RGB_TO_XYZ(r, g, b, X, Y, Z);
27-
28-
// Convert XYZ to xy chromaticity coordinates
29-
float color_x = X / (X + Y + Z);
30-
float color_y = Y / (X + Y + Z);
31-
32-
// Convert normalized xy to 16-bit values
33-
x = (uint16_t)(color_x * 65535.0f);
34-
y = (uint16_t)(color_y * 65535.0f);
35-
}
36-
3719
void ZigbeeColorDimmerSwitch::bindCb(esp_zb_zdp_status_t zdo_status, void *user_ctx) {
3820
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
3921
log_i("Bound successfully!");
@@ -417,15 +399,13 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, esp
417399

418400
void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue) {
419401
if (_is_bound) {
420-
//Convert RGB to XY
421-
uint16_t color_x, color_y;
422-
calculateXY(red, green, blue, color_x, color_y);
402+
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
423403

424404
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
425405
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
426406
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
427-
cmd_req.color_x = color_x;
428-
cmd_req.color_y = color_y;
407+
cmd_req.color_x = xy_color.x;
408+
cmd_req.color_y = xy_color.y;
429409
cmd_req.transition_time = 0;
430410
log_v("Sending 'set light color' command");
431411
esp_zb_lock_acquire(portMAX_DELAY);
@@ -438,16 +418,14 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
438418

439419
void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint16_t group_addr) {
440420
if (_is_bound) {
441-
//Convert RGB to XY
442-
uint16_t color_x, color_y;
443-
calculateXY(red, green, blue, color_x, color_y);
421+
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
444422

445423
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
446424
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
447425
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
448426
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
449-
cmd_req.color_x = color_x;
450-
cmd_req.color_y = color_y;
427+
cmd_req.color_x = xy_color.x;
428+
cmd_req.color_y = xy_color.y;
451429
cmd_req.transition_time = 0;
452430
log_v("Sending 'set light color' command to group address 0x%x", group_addr);
453431
esp_zb_lock_acquire(portMAX_DELAY);
@@ -460,17 +438,15 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
460438

461439
void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, uint16_t short_addr) {
462440
if (_is_bound) {
463-
//Convert RGB to XY
464-
uint16_t color_x, color_y;
465-
calculateXY(red, green, blue, color_x, color_y);
441+
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
466442

467443
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
468444
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
469445
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
470446
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
471447
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
472-
cmd_req.color_x = color_x;
473-
cmd_req.color_y = color_y;
448+
cmd_req.color_x = xy_color.x;
449+
cmd_req.color_y = xy_color.y;
474450
cmd_req.transition_time = 0;
475451
log_v("Sending 'set light color' command to endpoint %d, address 0x%x", endpoint, short_addr);
476452
esp_zb_lock_acquire(portMAX_DELAY);
@@ -483,17 +459,15 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
483459

484460
void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
485461
if (_is_bound) {
486-
//Convert RGB to XY
487-
uint16_t color_x, color_y;
488-
calculateXY(red, green, blue, color_x, color_y);
462+
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
489463

490464
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
491465
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
492466
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
493467
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
494468
memcpy(cmd_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
495-
cmd_req.color_x = color_x;
496-
cmd_req.color_y = color_y;
469+
cmd_req.color_x = xy_color.x;
470+
cmd_req.color_y = xy_color.y;
497471
cmd_req.transition_time = 0;
498472
log_v(
499473
"Sending 'set light color' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],

0 commit comments

Comments
 (0)