feat(matter): New Matter Endpoint (#10628)
* feat(matter): add new endpoint - color temperature light --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
parent
ff613b3f29
commit
6bc3ce68fe
13 changed files with 829 additions and 5 deletions
|
|
@ -169,6 +169,8 @@ set(ARDUINO_LIBRARY_OpenThread_SRCS
|
||||||
set(ARDUINO_LIBRARY_Matter_SRCS
|
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/MatterUtil/ColorFormat.cpp
|
||||||
libraries/Matter/src/Matter.cpp)
|
libraries/Matter/src/Matter.cpp)
|
||||||
|
|
||||||
set(ARDUINO_LIBRARY_PPP_SRCS
|
set(ARDUINO_LIBRARY_PPP_SRCS
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ MatterDimmableLight DimmableLight;
|
||||||
|
|
||||||
// it will keep last OnOff & Brightness state stored, using Preferences
|
// it will keep last OnOff & Brightness state stored, using Preferences
|
||||||
Preferences matterPref;
|
Preferences matterPref;
|
||||||
const char *onOffPrefKey = "OnOffState";
|
const char *onOffPrefKey = "OnOff";
|
||||||
const char *brightnessPrefKey = "BrightnessState";
|
const char *brightnessPrefKey = "Brightness";
|
||||||
|
|
||||||
// set your board RGB LED pin here
|
// set your board RGB LED pin here
|
||||||
#ifdef RGB_BUILTIN
|
#ifdef RGB_BUILTIN
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ MatterOnOffLight OnOffLight;
|
||||||
|
|
||||||
// it will keep last OnOff state stored, using Preferences
|
// it will keep last OnOff state stored, using Preferences
|
||||||
Preferences matterPref;
|
Preferences matterPref;
|
||||||
const char *onOffPrefKey = "OnOffState";
|
const char *onOffPrefKey = "OnOff";
|
||||||
|
|
||||||
// set your board LED pin here
|
// set your board LED pin here
|
||||||
#ifdef LED_BUILTIN
|
#ifdef LED_BUILTIN
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
// 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 Temperature CW/WW Light Endpoint
|
||||||
|
MatterColorTemperatureLight CW_WW_Light;
|
||||||
|
|
||||||
|
// it will keep last OnOff & Brightness state stored, using Preferences
|
||||||
|
Preferences matterPref;
|
||||||
|
const char *onOffPrefKey = "OnOff";
|
||||||
|
const char *brightnessPrefKey = "Brightness";
|
||||||
|
const char *temperaturePrefKey = "Temperature";
|
||||||
|
|
||||||
|
// 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 Temperature Light
|
||||||
|
bool setLightState(bool state, uint8_t brightness, uint16_t temperature_Mireds) {
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
#ifdef RGB_BUILTIN
|
||||||
|
CtColor_t ct = {temperature_Mireds};
|
||||||
|
RgbColor_t rgb_ct = CTToRgb(ct);
|
||||||
|
// simple intensity correction
|
||||||
|
float brightnessPercent = (float)brightness / MatterColorTemperatureLight::MAX_BRIGHTNESS;
|
||||||
|
rgb_ct.r = brightnessPercent * rgb_ct.r;
|
||||||
|
rgb_ct.g = brightnessPercent * rgb_ct.g;
|
||||||
|
rgb_ct.b = brightnessPercent * rgb_ct.b;
|
||||||
|
// set the RGB LED
|
||||||
|
rgbLedWrite(ledPin, rgb_ct.r, rgb_ct.g, rgb_ct.b);
|
||||||
|
#else
|
||||||
|
// No Color RGB LED, just use the brightness to control the LED
|
||||||
|
analogWrite(ledPin, brightness);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
digitalWrite(ledPin, LOW);
|
||||||
|
}
|
||||||
|
// store last Brightness and OnOff state for when the Light is restarted / power goes off
|
||||||
|
matterPref.putUChar(brightnessPrefKey, brightness);
|
||||||
|
matterPref.putBool(onOffPrefKey, state);
|
||||||
|
matterPref.putUShort(temperaturePrefKey, temperature_Mireds);
|
||||||
|
// 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 brightness ~= 6% (15/255)
|
||||||
|
uint8_t lastBrightness = matterPref.getUChar(brightnessPrefKey, 15);
|
||||||
|
// default temperature ~= 454 Mireds (Warm White)
|
||||||
|
uint16_t lastTemperature = matterPref.getUShort(temperaturePrefKey, MatterColorTemperatureLight::WARM_WHITE_COLOR_TEMPERATURE);
|
||||||
|
CW_WW_Light.begin(lastOnOffState, lastBrightness, lastTemperature);
|
||||||
|
// set the callback function to handle the Light state change
|
||||||
|
CW_WW_Light.onChange(setLightState);
|
||||||
|
|
||||||
|
// lambda functions are used to set the attribute change callbacks
|
||||||
|
CW_WW_Light.onChangeOnOff([](bool state) {
|
||||||
|
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
CW_WW_Light.onChangeBrightness([](uint8_t level) {
|
||||||
|
Serial.printf("Light Brightness changed to %d\r\n", level);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
CW_WW_Light.onChangeColorTemperature([](uint16_t temperature) {
|
||||||
|
Serial.printf("Light Color Temperature changed to %d\r\n", temperature);
|
||||||
|
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 | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(),
|
||||||
|
CW_WW_Light.getColorTemperature()
|
||||||
|
);
|
||||||
|
// configure the Light based on initial on-off state and brightness
|
||||||
|
CW_WW_Light.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 | brightness: %d | Color Temperature: %d mireds \r\n", CW_WW_Light ? "ON" : "OFF", CW_WW_Light.getBrightness(),
|
||||||
|
CW_WW_Light.getColorTemperature()
|
||||||
|
);
|
||||||
|
// configure the Light based on initial on-off state and brightness
|
||||||
|
CW_WW_Light.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!");
|
||||||
|
CW_WW_Light.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.");
|
||||||
|
CW_WW_Light = false; // turn the light off
|
||||||
|
Matter.decommission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
libraries/Matter/examples/Matter_CW_WW_Light/ci.json
Normal file
7
libraries/Matter/examples/Matter_CW_WW_Light/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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,12 @@ Matter KEYWORD1
|
||||||
ArduinoMatter KEYWORD1
|
ArduinoMatter KEYWORD1
|
||||||
MatterOnOffLight KEYWORD1
|
MatterOnOffLight KEYWORD1
|
||||||
MatterDimmableLight KEYWORD1
|
MatterDimmableLight KEYWORD1
|
||||||
|
MatterColorTemperatureLight 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)
|
||||||
|
|
@ -30,12 +35,28 @@ setOnOff KEYWORD2
|
||||||
getOnOff KEYWORD2
|
getOnOff KEYWORD2
|
||||||
setBrightness KEYWORD2
|
setBrightness KEYWORD2
|
||||||
getBrightness KEYWORD2
|
getBrightness KEYWORD2
|
||||||
|
setColorTemperature KEYWORD2
|
||||||
|
getColorTemperature KEYWORD2
|
||||||
toggle KEYWORD2
|
toggle KEYWORD2
|
||||||
updateAccessory KEYWORD2
|
updateAccessory KEYWORD2
|
||||||
onChange KEYWORD2
|
onChange KEYWORD2
|
||||||
onChangeOnOff KEYWORD2
|
onChangeOnOff KEYWORD2
|
||||||
onChangeBrightness KEYWORD2
|
onChangeBrightness KEYWORD2
|
||||||
|
onChangeColorTemperature KEYWORD2
|
||||||
|
XYToRgb KEYWORD2
|
||||||
|
HsvToRgb KEYWORD2
|
||||||
|
CTToRgb KEYWORD2
|
||||||
|
RgbToHsv KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
|
MAX_BRIGHTNESS LITERAL1
|
||||||
|
MAX_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
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <esp_matter.h>
|
#include <esp_matter.h>
|
||||||
|
#include <MatterUtil/ColorFormat.h>
|
||||||
#include <MatterEndpoints/MatterOnOffLight.h>
|
#include <MatterEndpoints/MatterOnOffLight.h>
|
||||||
#include <MatterEndpoints/MatterDimmableLight.h>
|
#include <MatterEndpoints/MatterDimmableLight.h>
|
||||||
|
#include <MatterEndpoints/MatterColorTemperatureLight.h>
|
||||||
|
|
||||||
using namespace esp_matter;
|
using namespace esp_matter;
|
||||||
|
|
||||||
|
|
@ -47,6 +49,7 @@ public:
|
||||||
// list of Matter EndPoints Friend Classes
|
// list of Matter EndPoints Friend Classes
|
||||||
friend class MatterOnOffLight;
|
friend class MatterOnOffLight;
|
||||||
friend class MatterDimmableLight;
|
friend class MatterDimmableLight;
|
||||||
|
friend class MatterColorTemperatureLight;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _init();
|
static void _init();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
// 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/MatterColorTemperatureLight.h>
|
||||||
|
|
||||||
|
using namespace esp_matter;
|
||||||
|
using namespace esp_matter::endpoint;
|
||||||
|
using namespace chip::app::Clusters;
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::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 CW_WW Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_d("CW_WW Attr update callback: endpoint: %u, cluster: %u, attribute: %u, val: %u", endpoint_id, cluster_id, attribute_id, val->val.u32);
|
||||||
|
|
||||||
|
if (endpoint_id == getEndPointId()) {
|
||||||
|
switch (cluster_id) {
|
||||||
|
case OnOff::Id:
|
||||||
|
if (attribute_id == OnOff::Attributes::OnOff::Id) {
|
||||||
|
log_d("CW_WW 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, brightnessLevel, colorTemperatureLevel);
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
onOffState = val->val.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LevelControl::Id:
|
||||||
|
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
|
||||||
|
log_d("CW_WW Light Brightness changed to %d", val->val.u8);
|
||||||
|
if (_onChangeBrightnessCB != NULL) {
|
||||||
|
ret &= _onChangeBrightnessCB(val->val.u8);
|
||||||
|
}
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
ret &= _onChangeCB(onOffState, val->val.u8, colorTemperatureLevel);
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
brightnessLevel = val->val.u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColorControl::Id:
|
||||||
|
if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
|
||||||
|
log_d("CW_WW Light Temperature changed to %d", val->val.u16);
|
||||||
|
if (_onChangeTemperatureCB != NULL) {
|
||||||
|
ret &= _onChangeTemperatureCB(val->val.u16);
|
||||||
|
}
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
ret &= _onChangeCB(onOffState, brightnessLevel, val->val.u16);
|
||||||
|
}
|
||||||
|
if (ret == true) {
|
||||||
|
colorTemperatureLevel = val->val.u16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatterColorTemperatureLight::MatterColorTemperatureLight() {}
|
||||||
|
|
||||||
|
MatterColorTemperatureLight::~MatterColorTemperatureLight() {
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::begin(bool initialState, uint8_t brightness, uint16_t ColorTemperature) {
|
||||||
|
ArduinoMatter::_init();
|
||||||
|
color_temperature_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 = brightness;
|
||||||
|
light_config.level_control.lighting.start_up_current_level = nullptr;
|
||||||
|
brightnessLevel = brightness;
|
||||||
|
|
||||||
|
light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
|
||||||
|
light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
|
||||||
|
light_config.color_control.color_temperature.color_temperature_mireds = ColorTemperature;
|
||||||
|
light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr;
|
||||||
|
colorTemperatureLevel = ColorTemperature;
|
||||||
|
|
||||||
|
// endpoint handles can be used to add/modify clusters.
|
||||||
|
endpoint_t *endpoint = color_temperature_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this);
|
||||||
|
if (endpoint == nullptr) {
|
||||||
|
log_e("Failed to create CW_WW light endpoint");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEndPointId(endpoint::get_id(endpoint));
|
||||||
|
log_i("CW_WW 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);
|
||||||
|
|
||||||
|
cluster_t *color_control_cluster = cluster::get(endpoint, ColorControl::Id);
|
||||||
|
attribute_t *color_temp_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
|
||||||
|
attribute::set_deferred_persistence(color_temp_attribute);
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterColorTemperatureLight::end() {
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::setOnOff(bool newState) {
|
||||||
|
if (!started) {
|
||||||
|
log_e("Matter CW_WW 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 MatterColorTemperatureLight::updateAccessory() {
|
||||||
|
if (_onChangeCB != NULL) {
|
||||||
|
_onChangeCB(onOffState, brightnessLevel, colorTemperatureLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::getOnOff() {
|
||||||
|
return onOffState;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::toggle() {
|
||||||
|
return setOnOff(!onOffState);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::setBrightness(uint8_t newBrightness) {
|
||||||
|
if (!started) {
|
||||||
|
log_w("Matter CW_WW Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid processing the a "no-change"
|
||||||
|
if (brightnessLevel == newBrightness) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
brightnessLevel = newBrightness;
|
||||||
|
|
||||||
|
endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id);
|
||||||
|
cluster_t *cluster = cluster::get(endpoint, LevelControl::Id);
|
||||||
|
attribute_t *attribute = attribute::get(cluster, LevelControl::Attributes::CurrentLevel::Id);
|
||||||
|
|
||||||
|
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
|
||||||
|
if (val.val.u8 != brightnessLevel) {
|
||||||
|
val.val.u8 = brightnessLevel;
|
||||||
|
attribute::update(endpoint_id, LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id, &val);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MatterColorTemperatureLight::getBrightness() {
|
||||||
|
return brightnessLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatterColorTemperatureLight::setColorTemperature(uint16_t newTemperature) {
|
||||||
|
if (!started) {
|
||||||
|
log_w("Matter CW_WW Light device has not begun.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid processing the a "no-change"
|
||||||
|
if (colorTemperatureLevel == newTemperature) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorTemperatureLevel = newTemperature;
|
||||||
|
|
||||||
|
endpoint_t *endpoint = endpoint::get(node::get(), endpoint_id);
|
||||||
|
cluster_t *cluster = cluster::get(endpoint, ColorControl::Id);
|
||||||
|
attribute_t *attribute = attribute::get(cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
|
||||||
|
|
||||||
|
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
|
||||||
|
attribute::get_val(attribute, &val);
|
||||||
|
|
||||||
|
if (val.val.u16 != colorTemperatureLevel) {
|
||||||
|
val.val.u16 = colorTemperatureLevel;
|
||||||
|
attribute::update(endpoint_id, ColorControl::Id, ColorControl::Attributes::ColorTemperatureMireds::Id, &val);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t MatterColorTemperatureLight::getColorTemperature() {
|
||||||
|
return colorTemperatureLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatterColorTemperatureLight::operator bool() {
|
||||||
|
return getOnOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatterColorTemperatureLight::operator=(bool newState) {
|
||||||
|
setOnOff(newState);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
// 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 MatterColorTemperatureLight : public MatterEndPoint {
|
||||||
|
public:
|
||||||
|
static const uint8_t MAX_BRIGHTNESS = 255;
|
||||||
|
static const uint16_t MAX_COLOR_TEMPERATURE = 500;
|
||||||
|
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();
|
||||||
|
// default initial state is off, brightness is 64 (25%) and temperature is 370 (Soft White)
|
||||||
|
virtual bool begin(bool initialState = false, uint8_t brightness = 64, uint16_t colorTemperature = 370);
|
||||||
|
// 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 setBrightness(uint8_t newBrightness); // returns true if successful
|
||||||
|
uint8_t getBrightness(); // returns current brightness
|
||||||
|
|
||||||
|
bool setColorTemperature(uint16_t newTemperature); // returns true if successful
|
||||||
|
uint16_t getColorTemperature(); // returns current temperature
|
||||||
|
|
||||||
|
// 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 Light brightness value [0..255] is changed by the Matter Controller
|
||||||
|
using EndPointBrightnessCB = std::function<bool(uint8_t)>;
|
||||||
|
void onChangeBrightness(EndPointBrightnessCB onChangeCB) {
|
||||||
|
_onChangeBrightnessCB = onChangeCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User Callbqck for whenever the Light temperature value is changed by the Matter Controller
|
||||||
|
using EndPointTemperatureCB = std::function<bool(uint16_t)>;
|
||||||
|
void onChangeColorTemperature(EndPointTemperatureCB onChangeCB) {
|
||||||
|
_onChangeTemperatureCB = onChangeCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User Callback for whenever any parameter is changed by the Matter Controller
|
||||||
|
using EndPointCB = std::function<bool(bool, uint8_t, uint16_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)
|
||||||
|
uint8_t brightnessLevel = 0; // default initial brightness is 0, but it can be changed by begin(bool, uint8_t)
|
||||||
|
uint16_t colorTemperatureLevel = 0; // default initial color temperature is 0, but it can be changed by begin(bool, uint8_t, uint16_t)
|
||||||
|
EndPointOnOffCB _onChangeOnOffCB = NULL;
|
||||||
|
EndPointBrightnessCB _onChangeBrightnessCB = NULL;
|
||||||
|
EndPointTemperatureCB _onChangeTemperatureCB = NULL;
|
||||||
|
EndPointCB _onChangeCB = NULL;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||||
|
|
@ -94,6 +94,12 @@ bool MatterDimmableLight::begin(bool initialState, uint8_t brightness) {
|
||||||
|
|
||||||
setEndPointId(endpoint::get_id(endpoint));
|
setEndPointId(endpoint::get_id(endpoint));
|
||||||
log_i("Dimmable Light created with endpoint_id %d", getEndPointId());
|
log_i("Dimmable 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;
|
started = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ public:
|
||||||
|
|
||||||
MatterDimmableLight();
|
MatterDimmableLight();
|
||||||
~MatterDimmableLight();
|
~MatterDimmableLight();
|
||||||
// default initial state is off and brightness is 0
|
// default initial state is off and brightness is 64 (25%)
|
||||||
virtual bool begin(bool initialState = false, uint8_t brightness = 0);
|
virtual bool begin(bool initialState = false, uint8_t brightness = 64);
|
||||||
// this will just stop processing Light Matter events
|
// this will just stop processing Light Matter events
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
|
|
|
||||||
203
libraries/Matter/src/MatterUtil/ColorFormat.cpp
Normal file
203
libraries/Matter/src/MatterUtil/ColorFormat.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
47
libraries/Matter/src/MatterUtil/ColorFormat.h
Normal file
47
libraries/Matter/src/MatterUtil/ColorFormat.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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