diff --git a/device_hal/led_driver/gpio/led_driver.c b/device_hal/led_driver/gpio/led_driver.c index c8bb3e8a6..1f4265202 100644 --- a/device_hal/led_driver/gpio/led_driver.c +++ b/device_hal/led_driver/gpio/led_driver.c @@ -106,3 +106,8 @@ esp_err_t led_driver_set_temperature(led_driver_handle_t handle, uint32_t temper { return ESP_ERR_NOT_SUPPORTED; } + +esp_err_t led_driver_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y) +{ + return ESP_ERR_NOT_SUPPORTED; +} diff --git a/device_hal/led_driver/hollow_led/led_driver.c b/device_hal/led_driver/hollow_led/led_driver.c index 1bf9921db..9767f8fb7 100644 --- a/device_hal/led_driver/hollow_led/led_driver.c +++ b/device_hal/led_driver/hollow_led/led_driver.c @@ -64,3 +64,11 @@ esp_err_t led_driver_set_temperature(led_driver_handle_t handle, uint32_t temper return ESP_OK; } + +esp_err_t led_driver_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y) +{ + ESP_LOGI(TAG, "Setting XY to: x=%d, y=%d", x, y); + /* Set the XY color coordinates here */ + + return ESP_OK; +} diff --git a/device_hal/led_driver/include/color_format.h b/device_hal/led_driver/include/color_format.h index 53e4c5923..ff12b2b44 100644 --- a/device_hal/led_driver/include/color_format.h +++ b/device_hal/led_driver/include/color_format.h @@ -29,10 +29,17 @@ typedef struct { uint8_t blue; } RGB_color_t; +typedef struct { + uint16_t x; + uint16_t y; +} XY_color_t; + void temp_to_hs(uint32_t temperature, HS_color_t *HS); void hsv_to_rgb(HS_color_t HS, uint8_t brightness, RGB_color_t *RGB); +void xy_to_rgb(XY_color_t XY, uint8_t brightness, RGB_color_t *RGB); + #ifdef __cplusplus } #endif diff --git a/device_hal/led_driver/include/led_driver.h b/device_hal/led_driver/include/led_driver.h index 9f319d0a7..278f1b351 100644 --- a/device_hal/led_driver/include/led_driver.h +++ b/device_hal/led_driver/include/led_driver.h @@ -34,6 +34,7 @@ esp_err_t led_driver_set_brightness(led_driver_handle_t handle, uint8_t brightne esp_err_t led_driver_set_hue(led_driver_handle_t handle, uint16_t hue); esp_err_t led_driver_set_saturation(led_driver_handle_t handle, uint8_t saturation); esp_err_t led_driver_set_temperature(led_driver_handle_t handle, uint32_t temperature); +esp_err_t led_driver_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y); #ifdef __cplusplus } diff --git a/device_hal/led_driver/utils/color_format.c b/device_hal/led_driver/utils/color_format.c index 74cd7c7c6..08b62d360 100644 --- a/device_hal/led_driver/utils/color_format.c +++ b/device_hal/led_driver/utils/color_format.c @@ -12,6 +12,7 @@ // limitations under the License #include +#include void hsv_to_rgb(HS_color_t HS, uint8_t brightness, RGB_color_t *RGB) { @@ -99,3 +100,61 @@ void temp_to_hs(uint32_t temperature, HS_color_t *HS) HS->hue = temp_table[(temperature - 600) / 100].hue; HS->saturation = temp_table[(temperature - 600) / 100].saturation; } + +void xy_to_rgb(XY_color_t XY, uint8_t brightness, RGB_color_t *RGB) +{ + // Convert Matter xy coordinates (0-65536) to CIE xy coordinates (0.0-1.0) + float x = (float)XY.x / 65536.0f; + float y = (float)XY.y / 65536.0f; + float z = 1.0f - x - y; + + // Convert brightness (0-255) to Y value (0.0-1.0) + float Y = (float)brightness / 255.0f; + + // Convert from xy to XYZ + float X, Z; + if (y > 0.0f) { + X = (Y / y) * x; + Z = (Y / y) * z; + } else { + X = 0.0f; + Z = 0.0f; + } + + // Convert XYZ to RGB using D65 white point matrix + float r = X * 3.240479f - Y * 1.537150f - Z * 0.498535f; + float g = -X * 0.969256f + Y * 1.875992f + Z * 0.041556f; + float b = X * 0.055648f - Y * 0.204043f + Z * 1.057311f; + + // Apply reverse gamma correction + if (r <= 0.0031308f) { + r = 12.92f * r; + } else { + r = (1.0f + 0.055f) * powf(r, (1.0f / 2.4f)) - 0.055f; + } + + if (g <= 0.0031308f) { + g = 12.92f * g; + } else { + g = (1.0f + 0.055f) * powf(g, (1.0f / 2.4f)) - 0.055f; + } + + if (b <= 0.0031308f) { + b = 12.92f * b; + } else { + b = (1.0f + 0.055f) * powf(b, (1.0f / 2.4f)) - 0.055f; + } + + // Clamp values to [0, 1] range + if (r < 0.0f) r = 0.0f; + if (r > 1.0f) r = 1.0f; + if (g < 0.0f) g = 0.0f; + if (g > 1.0f) g = 1.0f; + if (b < 0.0f) b = 0.0f; + if (b > 1.0f) b = 1.0f; + + // Convert to 0-255 range + RGB->red = (uint8_t)(r * 255.0f); + RGB->green = (uint8_t)(g * 255.0f); + RGB->blue = (uint8_t)(b * 255.0f); +} diff --git a/device_hal/led_driver/vled/led_driver.c b/device_hal/led_driver/vled/led_driver.c index e311b3048..d555d6a7a 100644 --- a/device_hal/led_driver/vled/led_driver.c +++ b/device_hal/led_driver/vled/led_driver.c @@ -196,3 +196,11 @@ esp_err_t led_driver_set_temperature(led_driver_handle_t handle, uint32_t temper hsv_to_rgb(current_HS, brightness, &mRGB); return led_driver_set_RGB(handle); } + +esp_err_t led_driver_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y) +{ + uint8_t brightness = current_power ? current_brightness : 0; + XY_color_t xy_color = {x, y}; + xy_to_rgb(xy_color, brightness, &mRGB); + return led_driver_set_RGB(handle); +} diff --git a/device_hal/led_driver/ws2812/led_driver.c b/device_hal/led_driver/ws2812/led_driver.c index cdcb72030..33879e893 100644 --- a/device_hal/led_driver/ws2812/led_driver.c +++ b/device_hal/led_driver/ws2812/led_driver.c @@ -114,3 +114,11 @@ esp_err_t led_driver_set_temperature(led_driver_handle_t handle, uint32_t temper hsv_to_rgb(current_HS, brightness, &mRGB); return led_driver_set_RGB(handle); } + +esp_err_t led_driver_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y) +{ + uint8_t brightness = current_power ? current_brightness : 0; + XY_color_t xy_color = {x, y}; + xy_to_rgb(xy_color, brightness, &mRGB); + return led_driver_set_RGB(handle); +} diff --git a/examples/light/main/app_driver.cpp b/examples/light/main/app_driver.cpp index f0984f14d..819477497 100644 --- a/examples/light/main/app_driver.cpp +++ b/examples/light/main/app_driver.cpp @@ -23,6 +23,10 @@ using namespace esp_matter; static const char *TAG = "app_driver"; extern uint16_t light_endpoint_id; +// Global variables to store current XY color coordinates +static uint16_t current_x = 0; +static uint16_t current_y = 0; + /* Do any conversions/remapping for the actual value here */ static esp_err_t app_driver_light_set_power(led_driver_handle_t handle, esp_matter_attr_val_t *val) { @@ -53,6 +57,11 @@ static esp_err_t app_driver_light_set_temperature(led_driver_handle_t handle, es return led_driver_set_temperature(handle, value); } +static esp_err_t app_driver_light_set_xy(led_driver_handle_t handle, uint16_t x, uint16_t y) +{ + return led_driver_set_xy(handle, x, y); +} + static void app_driver_button_toggle_cb(void *arg, void *data) { ESP_LOGI(TAG, "Toggle button pressed"); @@ -89,6 +98,12 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_ err = app_driver_light_set_saturation(handle, val); } else if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) { err = app_driver_light_set_temperature(handle, val); + } else if (attribute_id == ColorControl::Attributes::CurrentX::Id) { + current_x = val->val.u16; + err = app_driver_light_set_xy(handle, current_x, current_y); + } else if (attribute_id == ColorControl::Attributes::CurrentY::Id) { + current_y = val->val.u16; + err = app_driver_light_set_xy(handle, current_x, current_y); } } } @@ -124,6 +139,15 @@ esp_err_t app_driver_light_set_defaults(uint16_t endpoint_id) attribute = attribute::get(endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorTemperatureMireds::Id); attribute::get_val(attribute, &val); err |= app_driver_light_set_temperature(handle, &val); + } else if (val.val.u8 == (uint8_t)ColorControl::ColorMode::kCurrentXAndCurrentY) { + /* Setting XY coordinates */ + attribute = attribute::get(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentX::Id); + attribute::get_val(attribute, &val); + current_x = val.val.u16; + attribute = attribute::get(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentY::Id); + attribute::get_val(attribute, &val); + current_y = val.val.u16; + err |= app_driver_light_set_xy(handle, current_x, current_y); } else { ESP_LOGE(TAG, "Color mode not supported"); } diff --git a/examples/light/main/app_main.cpp b/examples/light/main/app_main.cpp index 9408593e8..caaf6a5fb 100644 --- a/examples/light/main/app_main.cpp +++ b/examples/light/main/app_main.cpp @@ -201,7 +201,7 @@ extern "C" void app_main() light_config.on_off.feature_flags = cluster::on_off::feature::lighting::get_id(); light_config.level_control.feature_flags = cluster::level_control::feature::lighting::get_id(); - light_config.color_control.feature_flags = cluster::color_control::feature::color_temperature::get_id(); + light_config.color_control.feature_flags = cluster::color_control::feature::color_temperature::get_id() | cluster::color_control::feature::xy::get_id(); // endpoint handles can be used to add/modify clusters. endpoint_t *endpoint = extended_color_light::create(node, &light_config, ENDPOINT_FLAG_NONE, light_handle);