feat(Matter): add new MatterColorLight endpoint (#10654)
* feat(matter): adds Matter Color Light endpoint
This commit is contained in:
parent
0f3191e34f
commit
414e4f3233
15 changed files with 978 additions and 282 deletions
|
|
@ -25,6 +25,7 @@ endif()
|
||||||
set(CORE_SRCS
|
set(CORE_SRCS
|
||||||
cores/esp32/base64.cpp
|
cores/esp32/base64.cpp
|
||||||
cores/esp32/cbuf.cpp
|
cores/esp32/cbuf.cpp
|
||||||
|
cores/esp32/ColorFormat.c
|
||||||
cores/esp32/chip-debug-report.cpp
|
cores/esp32/chip-debug-report.cpp
|
||||||
cores/esp32/esp32-hal-adc.c
|
cores/esp32/esp32-hal-adc.c
|
||||||
cores/esp32/esp32-hal-bt.c
|
cores/esp32/esp32-hal-bt.c
|
||||||
|
|
@ -170,7 +171,7 @@ set(ARDUINO_LIBRARY_Matter_SRCS
|
||||||
libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp
|
libraries/Matter/src/MatterEndpoints/MatterOnOffLight.cpp
|
||||||
libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp
|
libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp
|
||||||
libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp
|
libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp
|
||||||
libraries/Matter/src/MatterUtil/ColorFormat.cpp
|
libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp
|
||||||
libraries/Matter/src/Matter.cpp)
|
libraries/Matter/src/Matter.cpp)
|
||||||
|
|
||||||
set(ARDUINO_LIBRARY_PPP_SRCS
|
set(ARDUINO_LIBRARY_PPP_SRCS
|
||||||
|
|
|
||||||
279
cores/esp32/ColorFormat.c
Normal file
279
cores/esp32/ColorFormat.c
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Project CHIP Authors
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ColorFormat.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// define a clamp macro to substitute the std::clamp macro which is available from C++17 onwards
|
||||||
|
#define clamp(a, min, max) ((a) < (min) ? (min) : ((a) > (max) ? (max) : (a)))
|
||||||
|
|
||||||
|
const espHsvColor_t HSV_BLACK = {0, 0, 0};
|
||||||
|
const espHsvColor_t HSV_WHITE = {0, 0, 254};
|
||||||
|
const espHsvColor_t HSV_RED = {0, 254, 254};
|
||||||
|
const espHsvColor_t HSV_YELLOW = {42, 254, 254};
|
||||||
|
const espHsvColor_t HSV_GREEN = {84, 254, 254};
|
||||||
|
const espHsvColor_t HSV_CYAN = {127, 254, 254};
|
||||||
|
const espHsvColor_t HSV_BLUE = {169, 254, 254};
|
||||||
|
const espHsvColor_t HSV_MAGENTA = {211, 254, 254};
|
||||||
|
|
||||||
|
const espRgbColor_t RGB_BLACK = {0, 0, 0};
|
||||||
|
const espRgbColor_t RGB_WHITE = {255, 255, 255};
|
||||||
|
const espRgbColor_t RGB_RED = {255, 0, 0};
|
||||||
|
const espRgbColor_t RGB_YELLOW = {255, 255, 0};
|
||||||
|
const espRgbColor_t RGB_GREEN = {0, 255, 0};
|
||||||
|
const espRgbColor_t RGB_CYAN = {0, 255, 255};
|
||||||
|
const espRgbColor_t RGB_BLUE = {0, 0, 255};
|
||||||
|
const espRgbColor_t RGB_MAGENTA = {255, 0, 255};
|
||||||
|
|
||||||
|
// main color temperature values
|
||||||
|
const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE = {142};
|
||||||
|
const espCtColor_t DAYLIGHT_WHITE_COLOR_TEMPERATURE = {181};
|
||||||
|
const espCtColor_t WHITE_COLOR_TEMPERATURE = {250};
|
||||||
|
const espCtColor_t SOFT_WHITE_COLOR_TEMPERATURE = {370};
|
||||||
|
const espCtColor_t WARM_WHITE_COLOR_TEMPERATURE = {454};
|
||||||
|
|
||||||
|
espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v) {
|
||||||
|
espHsvColor_t hsv = {h, s, v};
|
||||||
|
return espHsvColorToRgbColor(hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv) {
|
||||||
|
espRgbColor_t rgb;
|
||||||
|
|
||||||
|
uint8_t region, p, q, t;
|
||||||
|
uint32_t h, s, v, remainder;
|
||||||
|
|
||||||
|
if (hsv.s == 0) {
|
||||||
|
rgb.r = rgb.g = rgb.b = hsv.v;
|
||||||
|
} else {
|
||||||
|
h = hsv.h;
|
||||||
|
s = hsv.s;
|
||||||
|
v = hsv.v;
|
||||||
|
|
||||||
|
region = h / 43;
|
||||||
|
remainder = (h - (region * 43)) * 6;
|
||||||
|
p = (v * (255 - s)) >> 8;
|
||||||
|
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
||||||
|
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
||||||
|
switch (region) {
|
||||||
|
case 0: rgb.r = v, rgb.g = t, rgb.b = p; break;
|
||||||
|
case 1: rgb.r = q, rgb.g = v, rgb.b = p; break;
|
||||||
|
case 2: rgb.r = p, rgb.g = v, rgb.b = t; break;
|
||||||
|
case 3: rgb.r = p, rgb.g = q, rgb.b = v; break;
|
||||||
|
case 4: rgb.r = t, rgb.g = p, rgb.b = v; break;
|
||||||
|
case 5:
|
||||||
|
default: rgb.r = v, rgb.g = p, rgb.b = q; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
espRgbColor_t rgb = {r, g, b};
|
||||||
|
return espRgbColorToHsvColor(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb) {
|
||||||
|
espHsvColor_t hsv;
|
||||||
|
uint8_t rgbMin, rgbMax;
|
||||||
|
|
||||||
|
rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
|
||||||
|
rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
|
||||||
|
|
||||||
|
hsv.v = rgbMax;
|
||||||
|
if (hsv.v == 0) {
|
||||||
|
hsv.h = 0;
|
||||||
|
hsv.s = 0;
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
hsv.s = 255 * (rgbMax - rgbMin) / hsv.v;
|
||||||
|
if (hsv.s == 0) {
|
||||||
|
hsv.h = 0;
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
if (rgbMax == rgb.r) {
|
||||||
|
hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
|
||||||
|
} else if (rgbMax == rgb.g) {
|
||||||
|
hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
|
||||||
|
} else {
|
||||||
|
hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
|
||||||
|
}
|
||||||
|
return hsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t espXYColorToRgbColor(uint8_t Level, espXyColor_t xy) {
|
||||||
|
return espXYToRgbColor(Level, xy.x, xy.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y) {
|
||||||
|
// convert xyY color space to RGB
|
||||||
|
|
||||||
|
// https://www.easyrgb.com/en/math.php
|
||||||
|
// https://en.wikipedia.org/wiki/SRGB
|
||||||
|
// refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
|
||||||
|
|
||||||
|
// The current_X/current_Y attribute contains the current value of the normalized chromaticity value of x/y.
|
||||||
|
// The value of x/y shall be related to the current_X/current_Y attribute by the relationship
|
||||||
|
// x = current_X/65536
|
||||||
|
// y = current_Y/65536
|
||||||
|
// z = 1-x-y
|
||||||
|
|
||||||
|
espRgbColor_t rgb;
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
float X, Y, Z;
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
x = ((float)current_X) / 65535.0f;
|
||||||
|
y = ((float)current_Y) / 65535.0f;
|
||||||
|
|
||||||
|
z = 1.0f - x - y;
|
||||||
|
|
||||||
|
// Calculate XYZ values
|
||||||
|
|
||||||
|
// Y - given brightness in 0 - 1 range
|
||||||
|
Y = ((float)Level) / 254.0f;
|
||||||
|
X = (Y / y) * x;
|
||||||
|
Z = (Y / y) * z;
|
||||||
|
|
||||||
|
// X, Y and Z input refer to a D65/2° standard illuminant.
|
||||||
|
// sR, sG and sB (standard RGB) output range = 0 ÷ 255
|
||||||
|
// convert XYZ to RGB - CIE XYZ to sRGB
|
||||||
|
X = X / 100.0f;
|
||||||
|
Y = Y / 100.0f;
|
||||||
|
Z = Z / 100.0f;
|
||||||
|
|
||||||
|
r = (X * 3.2406f) - (Y * 1.5372f) - (Z * 0.4986f);
|
||||||
|
g = -(X * 0.9689f) + (Y * 1.8758f) + (Z * 0.0415f);
|
||||||
|
b = (X * 0.0557f) - (Y * 0.2040f) + (Z * 1.0570f);
|
||||||
|
|
||||||
|
// apply gamma 2.2 correction
|
||||||
|
r = (r <= 0.0031308f ? 12.92f * r : (1.055f) * pow(r, (1.0f / 2.4f)) - 0.055f);
|
||||||
|
g = (g <= 0.0031308f ? 12.92f * g : (1.055f) * pow(g, (1.0f / 2.4f)) - 0.055f);
|
||||||
|
b = (b <= 0.0031308f ? 12.92f * b : (1.055f) * pow(b, (1.0f / 2.4f)) - 0.055f);
|
||||||
|
|
||||||
|
// Round off
|
||||||
|
r = clamp(r, 0, 1);
|
||||||
|
g = clamp(g, 0, 1);
|
||||||
|
b = clamp(b, 0, 1);
|
||||||
|
|
||||||
|
// these rgb values are in the range of 0 to 1, convert to limit of HW specific LED
|
||||||
|
rgb.r = (uint8_t)(r * 255);
|
||||||
|
rgb.g = (uint8_t)(g * 255);
|
||||||
|
rgb.b = (uint8_t)(b * 255);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
espRgbColor_t rgb = {r, g, b};
|
||||||
|
return espRgbColorToXYColor(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb) {
|
||||||
|
// convert RGB to xy color space
|
||||||
|
|
||||||
|
// https://www.easyrgb.com/en/math.php
|
||||||
|
// https://en.wikipedia.org/wiki/SRGB
|
||||||
|
// refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
|
||||||
|
|
||||||
|
espXyColor_t xy;
|
||||||
|
|
||||||
|
float r, g, b;
|
||||||
|
float X, Y, Z;
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
r = ((float)rgb.r) / 255.0f;
|
||||||
|
g = ((float)rgb.g) / 255.0f;
|
||||||
|
b = ((float)rgb.b) / 255.0f;
|
||||||
|
|
||||||
|
// convert RGB to XYZ - sRGB to CIE XYZ
|
||||||
|
r = (r <= 0.04045f ? r / 12.92f : pow((r + 0.055f) / 1.055f, 2.4f));
|
||||||
|
g = (g <= 0.04045f ? g / 12.92f : pow((g + 0.055f) / 1.055f, 2.4f));
|
||||||
|
b = (b <= 0.04045f ? b / 12.92f : pow((b + 0.055f) / 1.055f, 2.4f));
|
||||||
|
|
||||||
|
// https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d
|
||||||
|
X = r * 0.649926f + g * 0.103455f + b * 0.197109f;
|
||||||
|
Y = r * 0.234327f + g * 0.743075f + b * 0.022598f;
|
||||||
|
Z = r * 0.0000000f + g * 0.053077f + b * 1.035763f;
|
||||||
|
|
||||||
|
// sR, sG and sB (standard RGB) input range = 0 ÷ 255
|
||||||
|
// X, Y and Z output refer to a D65/2° standard illuminant.
|
||||||
|
X = r * 0.4124564f + g * 0.3575761f + b * 0.1804375f;
|
||||||
|
Y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f;
|
||||||
|
Z = r * 0.0193339f + g * 0.1191920f + b * 0.9503041f;
|
||||||
|
|
||||||
|
// Calculate xy values
|
||||||
|
x = X / (X + Y + Z);
|
||||||
|
y = Y / (X + Y + Z);
|
||||||
|
|
||||||
|
// convert to 0-65535 range
|
||||||
|
xy.x = (uint16_t)(x * 65535);
|
||||||
|
xy.y = (uint16_t)(y * 65535);
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t espCTToRgbColor(uint16_t ct) {
|
||||||
|
espCtColor_t ctColor = {ct};
|
||||||
|
return espCTColorToRgbColor(ctColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t espCTColorToRgbColor(espCtColor_t ct) {
|
||||||
|
espRgbColor_t rgb = {0, 0, 0};
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
if (ct.ctMireds == 0) {
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
// Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
|
||||||
|
|
||||||
|
// Convert Mireds to centiKelvins. k = 1,000,000/mired
|
||||||
|
float ctCentiKelvin = 10000 / ct.ctMireds;
|
||||||
|
|
||||||
|
// Red
|
||||||
|
if (ctCentiKelvin <= 66) {
|
||||||
|
r = 255;
|
||||||
|
} else {
|
||||||
|
r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Green
|
||||||
|
if (ctCentiKelvin <= 66) {
|
||||||
|
g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f;
|
||||||
|
} else {
|
||||||
|
g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blue
|
||||||
|
if (ctCentiKelvin >= 66) {
|
||||||
|
b = 255;
|
||||||
|
} else {
|
||||||
|
if (ctCentiKelvin <= 19) {
|
||||||
|
b = 0;
|
||||||
|
} else {
|
||||||
|
b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rgb.r = (uint8_t)clamp(r, 0, 255);
|
||||||
|
rgb.g = (uint8_t)clamp(g, 0, 255);
|
||||||
|
rgb.b = (uint8_t)clamp(b, 0, 255);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
70
cores/esp32/ColorFormat.h
Normal file
70
cores/esp32/ColorFormat.h
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Project CHIP Authors
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct RgbColor_t {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HsvColor_t {
|
||||||
|
uint16_t h;
|
||||||
|
uint8_t s;
|
||||||
|
uint8_t v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XyColor_t {
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CtColor_t {
|
||||||
|
uint16_t ctMireds;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct RgbColor_t espRgbColor_t;
|
||||||
|
typedef struct HsvColor_t espHsvColor_t;
|
||||||
|
typedef struct XyColor_t espXyColor_t;
|
||||||
|
typedef struct CtColor_t espCtColor_t;
|
||||||
|
|
||||||
|
espRgbColor_t espXYToRgbColor(uint8_t Level, uint16_t current_X, uint16_t current_Y);
|
||||||
|
espRgbColor_t espXYColorToRgb(uint8_t Level, espXyColor_t xy);
|
||||||
|
espXyColor_t espRgbColorToXYColor(espRgbColor_t rgb);
|
||||||
|
espXyColor_t espRgbToXYColor(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
espRgbColor_t espHsvColorToRgbColor(espHsvColor_t hsv);
|
||||||
|
espRgbColor_t espHsvToRgbColor(uint16_t h, uint8_t s, uint8_t v);
|
||||||
|
espRgbColor_t espCTColorToRgbColor(espCtColor_t ct);
|
||||||
|
espRgbColor_t espCTToRgbColor(uint16_t ct);
|
||||||
|
espHsvColor_t espRgbColorToHsvColor(espRgbColor_t rgb);
|
||||||
|
espHsvColor_t espRgbToHsvColor(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
||||||
|
extern const espHsvColor_t HSV_BLACK, HSV_WHITE, HSV_RED, HSV_YELLOW, HSV_GREEN, HSV_CYAN, HSV_BLUE, HSV_MAGENTA;
|
||||||
|
extern const espCtColor_t COOL_WHITE_COLOR_TEMPERATURE, DAYLIGHT_WHITE_COLOR_TEMPERATURE, WHITE_COLOR_TEMPERATURE, SOFT_WHITE_COLOR_TEMPERATURE,
|
||||||
|
WARM_WHITE_COLOR_TEMPERATURE;
|
||||||
|
extern const espRgbColor_t RGB_BLACK, RGB_WHITE, RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -6,14 +6,50 @@
|
||||||
# Datatypes (KEYWORD1)
|
# Datatypes (KEYWORD1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
Serial4 KEYWORD1
|
Serial4 KEYWORD1
|
||||||
|
espCtColor_t KEYWORD1
|
||||||
|
espXyColor_t KEYWORD1
|
||||||
|
espHsvColor_t KEYWORD1
|
||||||
|
espRgbColor_t KEYWORD1
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
|
espXYToRgbColor KEYWORD2
|
||||||
|
espXYColorToRgb KEYWORD2
|
||||||
|
espRgbColorToXYColor KEYWORD2
|
||||||
|
espRgbToXYColor KEYWORD2
|
||||||
|
espHsvColorToRgbColor KEYWORD2
|
||||||
|
espHsvToRgbColor KEYWORD2
|
||||||
|
espCTColorToRgbColor KEYWORD2
|
||||||
|
espCTToRgbColor KEYWORD2
|
||||||
|
espRgbColorToHsvColor KEYWORD2
|
||||||
|
espRgbToHsvColor KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
RGB_BUILTIN LITERAL1
|
RGB_BUILTIN LITERAL1
|
||||||
|
HSV_BLACK LITERAL1
|
||||||
|
HSV_WHITE LITERAL1
|
||||||
|
HSV_RED LITERAL1
|
||||||
|
HSV_YELLOW LITERAL1
|
||||||
|
HSV_GREEN LITERAL1
|
||||||
|
HSV_CYAN LITERAL1
|
||||||
|
HSV_BLUE LITERAL1
|
||||||
|
HSV_MAGENTA LITERAL1
|
||||||
|
COOL_WHITE_COLOR_TEMPERATURE LITERAL1
|
||||||
|
DAYLIGHT_WHITE_COLOR_TEMPERATURE LITERAL1
|
||||||
|
WHITE_COLOR_TEMPERATURE LITERAL1
|
||||||
|
SOFT_WHITE_COLOR_TEMPERATURE LITERAL1
|
||||||
|
WARM_WHITE_COLOR_TEMPERATURE LITERAL1
|
||||||
|
RGB_BLACK LITERAL1
|
||||||
|
RGB_WHITE LITERAL1
|
||||||
|
RGB_RED LITERAL1
|
||||||
|
RGB_YELLOW LITERAL1
|
||||||
|
RGB_GREEN LITERAL1
|
||||||
|
RGB_CYAN LITERAL1
|
||||||
|
RGB_BLUE LITERAL1
|
||||||
|
RGB_MAGENTA LITERAL1
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,7 @@ bool setLightState(bool state, uint8_t brightness, uint16_t temperature_Mireds)
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
#ifdef RGB_BUILTIN
|
#ifdef RGB_BUILTIN
|
||||||
CtColor_t ct = {temperature_Mireds};
|
espRgbColor_t rgb_ct = espCTToRgbColor(temperature_Mireds);
|
||||||
RgbColor_t rgb_ct = CTToRgb(ct);
|
|
||||||
// simple intensity correction
|
// simple intensity correction
|
||||||
float brightnessPercent = (float)brightness / MatterColorTemperatureLight::MAX_BRIGHTNESS;
|
float brightnessPercent = (float)brightness / MatterColorTemperatureLight::MAX_BRIGHTNESS;
|
||||||
rgb_ct.r = brightnessPercent * rgb_ct.r;
|
rgb_ct.r = brightnessPercent * rgb_ct.r;
|
||||||
|
|
@ -106,7 +105,7 @@ void setup() {
|
||||||
// default brightness ~= 6% (15/255)
|
// default brightness ~= 6% (15/255)
|
||||||
uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15);
|
uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15);
|
||||||
// default temperature ~= 454 Mireds (Warm White)
|
// default temperature ~= 454 Mireds (Warm White)
|
||||||
uint16_t lastTemperature = matterPref.getUShort(temperaturePrefKey, MatterColorTemperatureLight::WARM_WHITE_COLOR_TEMPERATURE);
|
uint16_t lastTemperature = matterPref.getUShort(temperaturePrefKey, WARM_WHITE_COLOR_TEMPERATURE.ctMireds);
|
||||||
CW_WW_Light.begin(lastOnOffState, lastBrightness, lastTemperature);
|
CW_WW_Light.begin(lastOnOffState, lastBrightness, lastTemperature);
|
||||||
// set the callback function to handle the Light state change
|
// set the callback function to handle the Light state change
|
||||||
CW_WW_Light.onChange(setLightState);
|
CW_WW_Light.onChange(setLightState);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Matter Manager
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
|
// List of Matter Endpoints for this Node
|
||||||
|
// Color Light Endpoint
|
||||||
|
MatterColorLight ColorLight;
|
||||||
|
|
||||||
|
// it will keep last OnOff & HSV Color state stored, using Preferences
|
||||||
|
Preferences matterPref;
|
||||||
|
const char *onOffPrefKey = "OnOff";
|
||||||
|
const char *hsvColorPrefKey = "HSV";
|
||||||
|
|
||||||
|
// set your board RGB LED pin here
|
||||||
|
#ifdef RGB_BUILTIN
|
||||||
|
const uint8_t ledPin = RGB_BUILTIN;
|
||||||
|
#else
|
||||||
|
const uint8_t ledPin = 2; // Set your pin here if your board has not defined LED_BUILTIN
|
||||||
|
#warning "Do not forget to set the RGB LED pin"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set your board USER BUTTON pin here
|
||||||
|
const uint8_t buttonPin = 0; // Set your pin here. Using BOOT Button. C6/C3 use GPIO9.
|
||||||
|
|
||||||
|
// WiFi is manually set and started
|
||||||
|
const char *ssid = "your-ssid"; // Change this to your WiFi SSID
|
||||||
|
const char *password = "your-password"; // Change this to your WiFi password
|
||||||
|
|
||||||
|
// Set the RGB LED Light based on the current state of the Color Light
|
||||||
|
bool setLightState(bool state, espHsvColor_t colorHSV) {
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
#ifdef RGB_BUILTIN
|
||||||
|
espRgbColor_t rgbColor = espHsvColorToRgbColor(colorHSV);
|
||||||
|
// set the RGB LED
|
||||||
|
rgbLedWrite(ledPin, rgbColor.r, rgbColor.g, rgbColor.b);
|
||||||
|
#else
|
||||||
|
// No Color RGB LED, just use the HSV value (brightness) to control the LED
|
||||||
|
analogWrite(ledPin, colorHSV.v);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
digitalWrite(ledPin, LOW);
|
||||||
|
}
|
||||||
|
// store last HSV Color and OnOff state for when the Light is restarted / power goes off
|
||||||
|
matterPref.putBool(onOffPrefKey, state);
|
||||||
|
matterPref.putUInt(hsvColorPrefKey, colorHSV.h << 16 | colorHSV.s << 8 | colorHSV.v);
|
||||||
|
// This callback must return the success state to Matter core
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize the USER BUTTON (Boot button) GPIO that will act as a toggle switch
|
||||||
|
pinMode(buttonPin, INPUT_PULLUP);
|
||||||
|
// Initialize the LED (light) GPIO and Matter End Point
|
||||||
|
pinMode(ledPin, OUTPUT);
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We start by connecting to a WiFi network
|
||||||
|
Serial.print("Connecting to ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
// enable IPv6
|
||||||
|
WiFi.enableIPv6(true);
|
||||||
|
// Manually connect to WiFi
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
// Wait for connection
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println("\r\nWiFi connected");
|
||||||
|
Serial.println("IP address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// Initialize Matter EndPoint
|
||||||
|
matterPref.begin("MatterPrefs", false);
|
||||||
|
// default OnOff state is ON if not stored before
|
||||||
|
bool lastOnOffState = matterPref.getBool(onOffPrefKey, true);
|
||||||
|
// default HSV color is blue HSV(169, 254, 254)
|
||||||
|
uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 169 << 16 | 254 << 8 | 254);
|
||||||
|
espHsvColor_t lastHsvColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)};
|
||||||
|
ColorLight.begin(lastOnOffState, lastHsvColor);
|
||||||
|
// set the callback function to handle the Light state change
|
||||||
|
ColorLight.onChange(setLightState);
|
||||||
|
|
||||||
|
// lambda functions are used to set the attribute change callbacks
|
||||||
|
ColorLight.onChangeOnOff([](bool state) {
|
||||||
|
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
ColorLight.onChangeColorHSV([](HsvColor_t hsvColor) {
|
||||||
|
Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Matter beginning - Last step, after all EndPoints are initialized
|
||||||
|
Matter.begin();
|
||||||
|
// This may be a restart of a already commissioned Matter accessory
|
||||||
|
if (Matter.isDeviceCommissioned()) {
|
||||||
|
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
|
||||||
|
Serial.printf(
|
||||||
|
"Initial state: %s | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g,
|
||||||
|
ColorLight.getColorRGB().b
|
||||||
|
);
|
||||||
|
// configure the Light based on initial on-off state and its color
|
||||||
|
ColorLight.updateAccessory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Button control
|
||||||
|
uint32_t button_time_stamp = 0; // debouncing control
|
||||||
|
bool button_state = false; // false = released | true = pressed
|
||||||
|
const uint32_t debouceTime = 250; // button debouncing time (ms)
|
||||||
|
const uint32_t decommissioningTimeout = 10000; // keep the button pressed for 10s to decommission the light
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Check Matter Light Commissioning state, which may change during execution of loop()
|
||||||
|
if (!Matter.isDeviceCommissioned()) {
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("Matter Node is not commissioned yet.");
|
||||||
|
Serial.println("Initiate the device discovery in your Matter environment.");
|
||||||
|
Serial.println("Commission it to your Matter hub with the manual pairing code or QR code");
|
||||||
|
Serial.printf("Manual pairing code: %s\r\n", Matter.getManualPairingCode().c_str());
|
||||||
|
Serial.printf("QR code URL: %s\r\n", Matter.getOnboardingQRCodeUrl().c_str());
|
||||||
|
// waits for Matter Light Commissioning.
|
||||||
|
uint32_t timeCount = 0;
|
||||||
|
while (!Matter.isDeviceCommissioned()) {
|
||||||
|
delay(100);
|
||||||
|
if ((timeCount++ % 50) == 0) { // 50*100ms = 5 sec
|
||||||
|
Serial.println("Matter Node not commissioned yet. Waiting for commissioning.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.printf(
|
||||||
|
"Initial state: %s | RGB Color: (%d,%d,%d) \r\n", ColorLight ? "ON" : "OFF", ColorLight.getColorRGB().r, ColorLight.getColorRGB().g,
|
||||||
|
ColorLight.getColorRGB().b
|
||||||
|
);
|
||||||
|
// configure the Light based on initial on-off state and its color
|
||||||
|
ColorLight.updateAccessory();
|
||||||
|
Serial.println("Matter Node is commissioned and connected to Wi-Fi. Ready for use.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A button is also used to control the light
|
||||||
|
// Check if the button has been pressed
|
||||||
|
if (digitalRead(buttonPin) == LOW && !button_state) {
|
||||||
|
// deals with button debouncing
|
||||||
|
button_time_stamp = millis(); // record the time while the button is pressed.
|
||||||
|
button_state = true; // pressed.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Onboard User Button is used as a Light toggle switch or to decommission it
|
||||||
|
uint32_t time_diff = millis() - button_time_stamp;
|
||||||
|
if (button_state && time_diff > debouceTime && digitalRead(buttonPin) == HIGH) {
|
||||||
|
button_state = false; // released
|
||||||
|
// Toggle button is released - toggle the light
|
||||||
|
Serial.println("User button released. Toggling Light!");
|
||||||
|
ColorLight.toggle(); // Matter Controller also can see the change
|
||||||
|
|
||||||
|
// Factory reset is triggered if the button is pressed longer than 10 seconds
|
||||||
|
if (time_diff > decommissioningTimeout) {
|
||||||
|
Serial.println("Decommissioning the Light Matter Accessory. It shall be commissioned again.");
|
||||||
|
ColorLight = false; // turn the light off
|
||||||
|
Matter.decommission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
libraries/Matter/examples/Matter_ColorLight/ci.json
Normal file
7
libraries/Matter/examples/Matter_ColorLight/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"fqbn_append": "PartitionScheme=huge_app",
|
||||||
|
"requires": [
|
||||||
|
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||||
|
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#######################################
|
#######################################
|
||||||
# Syntax Coloring Map For OpenThread
|
# Syntax Coloring Map For Matter
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
|
|
@ -10,12 +10,9 @@ Matter KEYWORD1
|
||||||
ArduinoMatter KEYWORD1
|
ArduinoMatter KEYWORD1
|
||||||
MatterOnOffLight KEYWORD1
|
MatterOnOffLight KEYWORD1
|
||||||
MatterDimmableLight KEYWORD1
|
MatterDimmableLight KEYWORD1
|
||||||
MatterColorTemperatureLight KEYWORD1
|
MatterColorTemperatureLight KEYWORD1
|
||||||
|
MatterColorLight KEYWORD1
|
||||||
MatterEndPoint KEYWORD1
|
MatterEndPoint KEYWORD1
|
||||||
CtColor_t KEYWORD1
|
|
||||||
XyColor_t KEYWORD1
|
|
||||||
HsvColor_t KEYWORD1
|
|
||||||
RgbColor_t KEYWORD1
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
|
@ -37,26 +34,23 @@ setBrightness KEYWORD2
|
||||||
getBrightness KEYWORD2
|
getBrightness KEYWORD2
|
||||||
setColorTemperature KEYWORD2
|
setColorTemperature KEYWORD2
|
||||||
getColorTemperature KEYWORD2
|
getColorTemperature KEYWORD2
|
||||||
|
setColorRGB KEYWORD2
|
||||||
|
getColorRGB KEYWORD2
|
||||||
|
setColorHSV KEYWORD2
|
||||||
|
getColorHSV KEYWORD2
|
||||||
toggle KEYWORD2
|
toggle KEYWORD2
|
||||||
updateAccessory KEYWORD2
|
updateAccessory KEYWORD2
|
||||||
onChange KEYWORD2
|
onChange KEYWORD2
|
||||||
onChangeOnOff KEYWORD2
|
onChangeOnOff KEYWORD2
|
||||||
onChangeBrightness KEYWORD2
|
onChangeBrightness KEYWORD2
|
||||||
onChangeColorTemperature KEYWORD2
|
onChangeColorTemperature KEYWORD2
|
||||||
XYToRgb KEYWORD2
|
onChangeColorHSV KEYWORD2
|
||||||
HsvToRgb KEYWORD2
|
|
||||||
CTToRgb KEYWORD2
|
|
||||||
RgbToHsv KEYWORD2
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
MAX_BRIGHTNESS LITERAL1
|
MAX_BRIGHTNESS LITERAL1
|
||||||
MAX_COLOR_TEMPERATURE LITERAL1
|
MAX_COLOR_TEMPERATURE LITERAL1
|
||||||
MIN_COLOR_TEMPERATURE LITERAL1
|
MIN_COLOR_TEMPERATURE LITERAL1
|
||||||
COOL_WHITE_COLOR_TEMPERATURE LITERAL1
|
|
||||||
DAYLIGHT_WHITE_COLOR_TEMPERATURE LITERAL1
|
|
||||||
WHITE_COLOR_TEMPERATURE LITERAL1
|
|
||||||
SOFT_WHITE_COLOR_TEMPERATURE LITERAL1
|
|
||||||
WARM_WHITE_COLOR_TEMPERATURE LITERAL1
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include <Matter.h>
|
#include <Matter.h>
|
||||||
#include <app/server/Server.h>
|
#include <app/server/Server.h>
|
||||||
#include "MatterEndPoint.h"
|
|
||||||
|
|
||||||
using namespace esp_matter;
|
using namespace esp_matter;
|
||||||
using namespace esp_matter::attribute;
|
using namespace esp_matter::attribute;
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,11 @@
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <esp_matter.h>
|
#include <esp_matter.h>
|
||||||
#include <MatterUtil/ColorFormat.h>
|
#include <ColorFormat.h>
|
||||||
#include <MatterEndpoints/MatterOnOffLight.h>
|
#include <MatterEndpoints/MatterOnOffLight.h>
|
||||||
#include <MatterEndpoints/MatterDimmableLight.h>
|
#include <MatterEndpoints/MatterDimmableLight.h>
|
||||||
#include <MatterEndpoints/MatterColorTemperatureLight.h>
|
#include <MatterEndpoints/MatterColorTemperatureLight.h>
|
||||||
|
#include <MatterEndpoints/MatterColorLight.h>
|
||||||
|
|
||||||
using namespace esp_matter;
|
using namespace esp_matter;
|
||||||
|
|
||||||
|
|
@ -50,6 +51,7 @@ public:
|
||||||
friend class MatterOnOffLight;
|
friend class MatterOnOffLight;
|
||||||
friend class MatterDimmableLight;
|
friend class MatterDimmableLight;
|
||||||
friend class MatterColorTemperatureLight;
|
friend class MatterColorTemperatureLight;
|
||||||
|
friend class MatterColorLight;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _init();
|
static void _init();
|
||||||
|
|
|
||||||
307
libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp
Normal file
307
libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp
Normal file
|
|
@ -0,0 +1,307 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||||
|
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <app/server/Server.h>
|
||||||
|
#include <MatterEndpoints/MatterColorLight.h>
|
||||||
|
|
||||||
|
using namespace esp_matter;
|
||||||
|
using namespace esp_matter::endpoint;
|
||||||
|
using namespace chip::app::Clusters;
|
||||||
|
|
||||||
|
// endpoint for color light device
|
||||||
|
namespace esp_matter {
|
||||||
|
using namespace cluster;
|
||||||
|
namespace endpoint {
|
||||||
|
namespace rgb_color_light {
|
||||||
|
typedef struct config {
|
||||||
|
cluster::descriptor::config_t descriptor;
|
||||||
|
cluster::identify::config_t identify;
|
||||||
|
cluster::groups::config_t groups;
|
||||||
|
cluster::scenes_management::config_t scenes_management;
|
||||||
|
cluster::on_off::config_t on_off;
|
||||||
|
cluster::level_control::config_t level_control;
|
||||||
|
cluster::color_control::config_t color_control;
|
||||||
|
} config_t;
|
||||||
|
|
||||||
|
uint32_t get_device_type_id() {
|
||||||
|
return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_device_type_version() {
|
||||||
|
return ESP_MATTER_EXTENDED_COLOR_LIGHT_DEVICE_TYPE_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t add(endpoint_t *endpoint, config_t *config) {
|
||||||
|
if (!endpoint) {
|
||||||
|
log_e("Endpoint cannot be NULL");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version());
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
log_e("Failed to add device type id:%" PRIu32 ",err: %d", get_device_type_id(), err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor::create(endpoint, &(config->descriptor), CLUSTER_FLAG_SERVER);
|
||||||
|
cluster_t *identify_cluster = identify::create(endpoint, &(config->identify), CLUSTER_FLAG_SERVER);
|
||||||
|
identify::command::create_trigger_effect(identify_cluster);
|
||||||
|
groups::create(endpoint, &(config->groups), CLUSTER_FLAG_SERVER);
|
||||||
|
cluster_t *scenes_cluster = scenes_management::create(endpoint, &(config->scenes_management), CLUSTER_FLAG_SERVER);
|
||||||
|
scenes_management::command::create_copy_scene(scenes_cluster);
|
||||||
|
scenes_management::command::create_copy_scene_response(scenes_cluster);
|
||||||
|
|
||||||
|
on_off::create(endpoint, &(config->on_off), CLUSTER_FLAG_SERVER, on_off::feature::lighting::get_id());
|
||||||
|
level_control::create(
|
||||||
|
endpoint, &(config->level_control), CLUSTER_FLAG_SERVER, level_control::feature::on_off::get_id() | level_control::feature::lighting::get_id()
|
||||||
|
);
|
||||||
|
color_control::create(endpoint, &(config->color_control), CLUSTER_FLAG_SERVER, color_control::feature::hue_saturation::get_id());
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data) {
|
||||||
|
endpoint_t *endpoint = endpoint::create(node, flags, priv_data);
|
||||||
|
add(endpoint, config);
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
} // namespace rgb_color_light
|
||||||
|
} // namespace endpoint
|
||||||
|
} // namespace esp_matter
|
||||||
|
|
||||||
|
bool MatterColorLight::attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) {
|
||||||
|
bool ret = true;
|
||||||
|
if (!started) {
|
||||||
|
log_e("Matter RGB Color Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_d(
|
||||||
|
"RGB Color Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u, type: %u", endpoint_id, cluster_id, attribute_id, val->val.u32,
|
||||||
|
val->type
|
||||||
|
);
|
||||||
|
|
||||||
|
if (endpoint_id == getEndPointId()) {
|
||||||
|
switch (cluster_id) {
|
||||||
|
case OnOff::Id:
|
||||||
|
if (attribute_id == OnOff::Attributes::OnOff::Id) {
|
||||||
|
log_d("RGB Color Light On/Off State changed to %d", val->val.b);
|
||||||
|
if (_onChangeOnOffCB != NULL) {
|
||||||
|
ret &= _onChangeOnOffCB(val->val.b);
|
||||||
|
}
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
ret &= _onChangeCB(val->val.b, colorHSV);
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
onOffState = val->val.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LevelControl::Id:
|
||||||
|
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
|
||||||
|
log_d("RGB Color Light Brightness changed to %d", val->val.u8);
|
||||||
|
if (_onChangeColorCB != NULL) {
|
||||||
|
ret &= _onChangeColorCB({colorHSV.h, colorHSV.s, val->val.u8});
|
||||||
|
}
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
ret &= _onChangeCB(onOffState, {colorHSV.h, colorHSV.s, val->val.u8});
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
colorHSV.v = val->val.u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColorControl::Id:
|
||||||
|
{
|
||||||
|
if (attribute_id != ColorControl::Attributes::CurrentHue::Id && attribute_id != ColorControl::Attributes::CurrentSaturation::Id) {
|
||||||
|
log_i("Color Control Attribute ID [%x] not processed.", attribute_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
espHsvColor_t hsvColor = {colorHSV.h, colorHSV.s, colorHSV.v};
|
||||||
|
if (attribute_id == ColorControl::Attributes::CurrentHue::Id) {
|
||||||
|
log_d("RGB Light Hue changed to %d", val->val.u8);
|
||||||
|
hsvColor.h = val->val.u8;
|
||||||
|
} else { // attribute_id == ColorControl::Attributes::CurrentSaturation::Id)
|
||||||
|
log_d("RGB Light Saturation changed to %d", val->val.u8);
|
||||||
|
hsvColor.s = val->val.u8;
|
||||||
|
}
|
||||||
|
if (_onChangeColorCB != NULL) {
|
||||||
|
ret &= _onChangeColorCB(hsvColor);
|
||||||
|
}
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
ret &= _onChangeCB(onOffState, hsvColor);
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
colorHSV = {hsvColor.h, hsvColor.s, hsvColor.v};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatterColorLight::MatterColorLight() {}
|
||||||
|
|
||||||
|
MatterColorLight::~MatterColorLight() {
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::begin(bool initialState, espHsvColor_t _colorHSV) {
|
||||||
|
ArduinoMatter::_init();
|
||||||
|
rgb_color_light::config_t light_config;
|
||||||
|
|
||||||
|
light_config.on_off.on_off = initialState;
|
||||||
|
light_config.on_off.lighting.start_up_on_off = nullptr;
|
||||||
|
onOffState = initialState;
|
||||||
|
|
||||||
|
light_config.level_control.current_level = _colorHSV.v;
|
||||||
|
light_config.level_control.lighting.start_up_current_level = nullptr;
|
||||||
|
|
||||||
|
light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation;
|
||||||
|
light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kCurrentHueAndCurrentSaturation;
|
||||||
|
light_config.color_control.hue_saturation.current_hue = _colorHSV.h;
|
||||||
|
light_config.color_control.hue_saturation.current_saturation = _colorHSV.s;
|
||||||
|
colorHSV = {_colorHSV.h, _colorHSV.s, _colorHSV.v};
|
||||||
|
|
||||||
|
// endpoint handles can be used to add/modify clusters.
|
||||||
|
endpoint_t *endpoint = rgb_color_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this);
|
||||||
|
if (endpoint == nullptr) {
|
||||||
|
log_e("Failed to create RGB Color light endpoint");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEndPointId(endpoint::get_id(endpoint));
|
||||||
|
log_i("RGB Color Light created with endpoint_id %d", getEndPointId());
|
||||||
|
|
||||||
|
/* Mark deferred persistence for some attributes that might be changed rapidly */
|
||||||
|
cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id);
|
||||||
|
attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id);
|
||||||
|
attribute::set_deferred_persistence(current_level_attribute);
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterColorLight::end() {
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::setOnOff(bool newState) {
|
||||||
|
if (!started) {
|
||||||
|
log_e("Matter RGB Color Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid processing the a "no-change"
|
||||||
|
if (onOffState == newState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onOffState = newState;
|
||||||
|
|
||||||
|
endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id);
|
||||||
|
cluster_t *cluster = cluster::get(endpoint, OnOff::Id);
|
||||||
|
attribute_t *attribute = attribute::get(cluster, OnOff::Attributes::OnOff::Id);
|
||||||
|
|
||||||
|
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
|
||||||
|
if (val.val.b != onOffState) {
|
||||||
|
val.val.b = onOffState;
|
||||||
|
attribute::update(endpoint_id, OnOff::Id, OnOff::Attributes::OnOff::Id, &val);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterColorLight::updateAccessory() {
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
_onChangeCB(onOffState, colorHSV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::getOnOff() {
|
||||||
|
return onOffState;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::toggle() {
|
||||||
|
return setOnOff(!onOffState);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::setColorRGB(espRgbColor_t _rgbColor) {
|
||||||
|
return setColorHSV(espRgbColorToHsvColor(_rgbColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
espRgbColor_t MatterColorLight::getColorRGB() {
|
||||||
|
return espHsvColorToRgbColor(colorHSV);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorLight::setColorHSV(espHsvColor_t _hsvColor) {
|
||||||
|
|
||||||
|
if (!started) {
|
||||||
|
log_w("Matter RGB Color Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid processing the a "no-change"
|
||||||
|
if (colorHSV.h == _hsvColor.h && colorHSV.s == _hsvColor.s && colorHSV.v == _hsvColor.v) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorHSV = {_hsvColor.h, _hsvColor.s, _hsvColor.v};
|
||||||
|
|
||||||
|
endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id);
|
||||||
|
cluster_t *cluster = cluster::get(endpoint, ColorControl::Id);
|
||||||
|
// update hue
|
||||||
|
attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::CurrentHue::Id);
|
||||||
|
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
if (val.val.u8 != colorHSV.h) {
|
||||||
|
val.val.u8 = colorHSV.h;
|
||||||
|
attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentHue::Id, &val);
|
||||||
|
}
|
||||||
|
// update saturation
|
||||||
|
attribute = attribute::get(cluster, ColorControl::Attributes::CurrentSaturation::Id);
|
||||||
|
val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
if (val.val.u8 != colorHSV.s) {
|
||||||
|
val.val.u8 = colorHSV.s;
|
||||||
|
attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::CurrentSaturation::Id, &val);
|
||||||
|
}
|
||||||
|
// update value (brightness)
|
||||||
|
cluster = cluster::get(endpoint, LevelControl::Id);
|
||||||
|
attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id);
|
||||||
|
val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
if (val.val.u8 != colorHSV.v) {
|
||||||
|
val.val.u8 = colorHSV.v;
|
||||||
|
attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
espHsvColor_t MatterColorLight::getColorHSV() {
|
||||||
|
return colorHSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatterColorLight::operator bool() {
|
||||||
|
return getOnOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterColorLight::operator=(bool newState) {
|
||||||
|
setOnOff(newState);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
75
libraries/Matter/src/MatterEndpoints/MatterColorLight.h
Normal file
75
libraries/Matter/src/MatterEndpoints/MatterColorLight.h
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#ifdef CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
|
||||||
|
|
||||||
|
#include <Matter.h>
|
||||||
|
#include <MatterEndPoint.h>
|
||||||
|
|
||||||
|
class MatterColorLight : public MatterEndPoint {
|
||||||
|
public:
|
||||||
|
MatterColorLight();
|
||||||
|
~MatterColorLight();
|
||||||
|
// default initial state is off, color is red 12% intensity HSV(0, 254, 31)
|
||||||
|
virtual bool begin(bool initialState = false, espHsvColor_t colorHSV = {0, 254, 31});
|
||||||
|
// this will just stop processing Light Matter events
|
||||||
|
void end();
|
||||||
|
|
||||||
|
bool setOnOff(bool newState); // returns true if successful
|
||||||
|
bool getOnOff(); // returns current light state
|
||||||
|
bool toggle(); // returns true if successful
|
||||||
|
|
||||||
|
bool setColorRGB(espRgbColor_t rgbColor); // returns true if successful
|
||||||
|
espRgbColor_t getColorRGB(); // returns current RGB Color
|
||||||
|
bool setColorHSV(espHsvColor_t hsvColor); // returns true if successful
|
||||||
|
espHsvColor_t getColorHSV(); // returns current HSV Color
|
||||||
|
|
||||||
|
// used to update the state of the light using the current Matter Light internal state
|
||||||
|
// It is necessary to set a user callback function using onChange() to handle the physical light state
|
||||||
|
void updateAccessory();
|
||||||
|
|
||||||
|
operator bool(); // returns current on/off light state
|
||||||
|
void operator=(bool state); // turns light on or off
|
||||||
|
|
||||||
|
// this function is called by Matter internal event processor. It could be overwritten by the application, if necessary.
|
||||||
|
bool attributeChangeCB(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val);
|
||||||
|
|
||||||
|
// User Callback for whenever the Light On/Off state is changed by the Matter Controller
|
||||||
|
using EndPointOnOffCB = std::function<bool(bool)>;
|
||||||
|
void onChangeOnOff(EndPointOnOffCB onChangeCB) {
|
||||||
|
_onChangeOnOffCB = onChangeCB;
|
||||||
|
}
|
||||||
|
// User Callback for whenever the HSV Color value is changed by the Matter Controller
|
||||||
|
using EndPointRGBColorCB = std::function<bool(espHsvColor_t)>;
|
||||||
|
void onChangeColorHSV(EndPointRGBColorCB onChangeCB) {
|
||||||
|
_onChangeColorCB = onChangeCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User Callback for whenever any parameter is changed by the Matter Controller
|
||||||
|
using EndPointCB = std::function<bool(bool, espHsvColor_t)>;
|
||||||
|
void onChange(EndPointCB onChangeCB) {
|
||||||
|
_onChangeCB = onChangeCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool started = false;
|
||||||
|
bool onOffState = false; // default initial state is off, but it can be changed by begin(bool)
|
||||||
|
espHsvColor_t colorHSV = {0}; // default initial color HSV is black, but it can be changed by begin(bool, espHsvColor_t)
|
||||||
|
EndPointOnOffCB _onChangeOnOffCB = NULL;
|
||||||
|
EndPointRGBColorCB _onChangeColorCB = NULL;
|
||||||
|
EndPointCB _onChangeCB = NULL;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
|
|
@ -24,12 +24,6 @@ public:
|
||||||
static const uint8_t MAX_BRIGHTNESS = 255;
|
static const uint8_t MAX_BRIGHTNESS = 255;
|
||||||
static const uint16_t MAX_COLOR_TEMPERATURE = 500;
|
static const uint16_t MAX_COLOR_TEMPERATURE = 500;
|
||||||
static const uint16_t MIN_COLOR_TEMPERATURE = 100;
|
static const uint16_t MIN_COLOR_TEMPERATURE = 100;
|
||||||
// main color temperature values
|
|
||||||
static const uint16_t COOL_WHITE_COLOR_TEMPERATURE = 142;
|
|
||||||
static const uint16_t DAYLIGHT_WHITE_COLOR_TEMPERATURE = 181;
|
|
||||||
static const uint16_t WHITE_COLOR_TEMPERATURE = 250;
|
|
||||||
static const uint16_t SOFT_WHITE_COLOR_TEMPERATURE = 370;
|
|
||||||
static const uint16_t WARM_WHITE_COLOR_TEMPERATURE = 454;
|
|
||||||
|
|
||||||
MatterColorTemperatureLight();
|
MatterColorTemperatureLight();
|
||||||
~MatterColorTemperatureLight();
|
~MatterColorTemperatureLight();
|
||||||
|
|
|
||||||
|
|
@ -1,203 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Project CHIP Authors
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ColorFormat.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
// define a clamp macro to substitute the std::clamp macro which is available from C++17 onwards
|
|
||||||
#define clamp(a, min, max) ((a) < (min) ? (min) : ((a) > (max) ? (max) : (a)))
|
|
||||||
|
|
||||||
RgbColor_t HsvToRgb(HsvColor_t hsv) {
|
|
||||||
RgbColor_t rgb;
|
|
||||||
|
|
||||||
uint16_t i = hsv.h / 60;
|
|
||||||
uint16_t rgb_max = hsv.v;
|
|
||||||
uint16_t rgb_min = (uint16_t)(rgb_max * (100 - hsv.s)) / 100;
|
|
||||||
uint16_t diff = hsv.h % 60;
|
|
||||||
uint16_t rgb_adj = (uint16_t)((rgb_max - rgb_min) * diff) / 60;
|
|
||||||
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
rgb.r = (uint8_t)rgb_max;
|
|
||||||
rgb.g = (uint8_t)(rgb_min + rgb_adj);
|
|
||||||
rgb.b = (uint8_t)rgb_min;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rgb.r = (uint8_t)(rgb_max - rgb_adj);
|
|
||||||
rgb.g = (uint8_t)rgb_max;
|
|
||||||
rgb.b = (uint8_t)rgb_min;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rgb.r = (uint8_t)rgb_min;
|
|
||||||
rgb.g = (uint8_t)rgb_max;
|
|
||||||
rgb.b = (uint8_t)(rgb_min + rgb_adj);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rgb.r = (uint8_t)rgb_min;
|
|
||||||
rgb.g = (uint8_t)(rgb_max - rgb_adj);
|
|
||||||
rgb.b = (uint8_t)rgb_max;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rgb.r = (uint8_t)(rgb_min + rgb_adj);
|
|
||||||
rgb.g = (uint8_t)rgb_min;
|
|
||||||
rgb.b = (uint8_t)rgb_max;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rgb.r = (uint8_t)rgb_max;
|
|
||||||
rgb.g = (uint8_t)rgb_min;
|
|
||||||
rgb.b = (uint8_t)(rgb_max - rgb_adj);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
HsvColor_t RgbToHsv(RgbColor_t rgb) {
|
|
||||||
HsvColor_t hsv;
|
|
||||||
|
|
||||||
uint16_t rgb_max = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
|
|
||||||
uint16_t rgb_min = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
|
|
||||||
uint16_t diff = rgb_max - rgb_min;
|
|
||||||
|
|
||||||
if (diff == 0) {
|
|
||||||
hsv.h = 0;
|
|
||||||
} else if (rgb_max == rgb.r) {
|
|
||||||
hsv.h = (uint8_t)(60 * ((rgb.g - rgb.b) * 100) / diff);
|
|
||||||
} else if (rgb_max == rgb.g) {
|
|
||||||
hsv.h = (uint8_t)(60 * (((rgb.b - rgb.r) * 100) / diff + 2 * 100));
|
|
||||||
} else {
|
|
||||||
hsv.h = (uint8_t)(60 * (((rgb.r - rgb.g) * 100) / diff + 4 * 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rgb_max == 0) {
|
|
||||||
hsv.s = 0;
|
|
||||||
} else {
|
|
||||||
hsv.s = (uint8_t)((diff * 100) / rgb_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
hsv.v = (uint8_t)rgb_max;
|
|
||||||
if (hsv.h < 0) {
|
|
||||||
hsv.h += 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hsv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RgbColor_t XYToRgb(uint8_t Level, uint16_t current_X, uint16_t current_Y) {
|
|
||||||
// convert xyY color space to RGB
|
|
||||||
|
|
||||||
// https://www.easyrgb.com/en/math.php
|
|
||||||
// https://en.wikipedia.org/wiki/SRGB
|
|
||||||
// refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
|
|
||||||
|
|
||||||
// The current_X/current_Y attribute contains the current value of the normalized chromaticity value of x/y.
|
|
||||||
// The value of x/y shall be related to the current_X/current_Y attribute by the relationship
|
|
||||||
// x = current_X/65536
|
|
||||||
// y = current_Y/65536
|
|
||||||
// z = 1-x-y
|
|
||||||
|
|
||||||
RgbColor_t rgb;
|
|
||||||
|
|
||||||
float x, y, z;
|
|
||||||
float X, Y, Z;
|
|
||||||
float r, g, b;
|
|
||||||
|
|
||||||
x = ((float)current_X) / 65535.0f;
|
|
||||||
y = ((float)current_Y) / 65535.0f;
|
|
||||||
|
|
||||||
z = 1.0f - x - y;
|
|
||||||
|
|
||||||
// Calculate XYZ values
|
|
||||||
|
|
||||||
// Y - given brightness in 0 - 1 range
|
|
||||||
Y = ((float)Level) / 254.0f;
|
|
||||||
X = (Y / y) * x;
|
|
||||||
Z = (Y / y) * z;
|
|
||||||
|
|
||||||
// X, Y and Z input refer to a D65/2° standard illuminant.
|
|
||||||
// sR, sG and sB (standard RGB) output range = 0 ÷ 255
|
|
||||||
// convert XYZ to RGB - CIE XYZ to sRGB
|
|
||||||
X = X / 100.0f;
|
|
||||||
Y = Y / 100.0f;
|
|
||||||
Z = Z / 100.0f;
|
|
||||||
|
|
||||||
r = (X * 3.2406f) - (Y * 1.5372f) - (Z * 0.4986f);
|
|
||||||
g = -(X * 0.9689f) + (Y * 1.8758f) + (Z * 0.0415f);
|
|
||||||
b = (X * 0.0557f) - (Y * 0.2040f) + (Z * 1.0570f);
|
|
||||||
|
|
||||||
// apply gamma 2.2 correction
|
|
||||||
r = (r <= 0.0031308f ? 12.92f * r : (1.055f) * pow(r, (1.0f / 2.4f)) - 0.055f);
|
|
||||||
g = (g <= 0.0031308f ? 12.92f * g : (1.055f) * pow(g, (1.0f / 2.4f)) - 0.055f);
|
|
||||||
b = (b <= 0.0031308f ? 12.92f * b : (1.055f) * pow(b, (1.0f / 2.4f)) - 0.055f);
|
|
||||||
|
|
||||||
// Round off
|
|
||||||
r = clamp(r, 0, 1);
|
|
||||||
g = clamp(g, 0, 1);
|
|
||||||
b = clamp(b, 0, 1);
|
|
||||||
|
|
||||||
// these rgb values are in the range of 0 to 1, convert to limit of HW specific LED
|
|
||||||
rgb.r = (uint8_t)(r * 255);
|
|
||||||
rgb.g = (uint8_t)(g * 255);
|
|
||||||
rgb.b = (uint8_t)(b * 255);
|
|
||||||
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
RgbColor_t CTToRgb(CtColor_t ct) {
|
|
||||||
RgbColor_t rgb = {0, 0, 0};
|
|
||||||
float r, g, b;
|
|
||||||
|
|
||||||
if (ct.ctMireds == 0) {
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
// Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
|
|
||||||
|
|
||||||
// Convert Mireds to centiKelvins. k = 1,000,000/mired
|
|
||||||
float ctCentiKelvin = 10000 / ct.ctMireds;
|
|
||||||
|
|
||||||
// Red
|
|
||||||
if (ctCentiKelvin <= 66) {
|
|
||||||
r = 255;
|
|
||||||
} else {
|
|
||||||
r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Green
|
|
||||||
if (ctCentiKelvin <= 66) {
|
|
||||||
g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f;
|
|
||||||
} else {
|
|
||||||
g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blue
|
|
||||||
if (ctCentiKelvin >= 66) {
|
|
||||||
b = 255;
|
|
||||||
} else {
|
|
||||||
if (ctCentiKelvin <= 19) {
|
|
||||||
b = 0;
|
|
||||||
} else {
|
|
||||||
b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rgb.r = (uint8_t)clamp(r, 0, 255);
|
|
||||||
rgb.g = (uint8_t)clamp(g, 0, 255);
|
|
||||||
rgb.b = (uint8_t)clamp(b, 0, 255);
|
|
||||||
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Project CHIP Authors
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct RgbColor_t {
|
|
||||||
uint8_t r;
|
|
||||||
uint8_t g;
|
|
||||||
uint8_t b;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HsvColor_t {
|
|
||||||
int16_t h;
|
|
||||||
uint8_t s;
|
|
||||||
uint8_t v;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct XyColor_t {
|
|
||||||
uint16_t x;
|
|
||||||
uint16_t y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CtColor_t {
|
|
||||||
uint16_t ctMireds;
|
|
||||||
};
|
|
||||||
|
|
||||||
RgbColor_t XYToRgb(uint8_t Level, uint16_t current_X, uint16_t current_Y);
|
|
||||||
RgbColor_t HsvToRgb(HsvColor_t hsv);
|
|
||||||
RgbColor_t CTToRgb(CtColor_t ct);
|
|
||||||
HsvColor_t RgbToHsv(RgbColor_t rgb);
|
|
||||||
Loading…
Reference in a new issue