feat(matter): Adds Matter Enhanced Color Light Endpoint (CW/WW/RGB) (#10657)
* feat(matter): created enhanced color light new matter endpoint and example
This commit is contained in:
parent
c2ce738cae
commit
9d8df8b315
8 changed files with 708 additions and 0 deletions
|
|
@ -172,6 +172,7 @@ set(ARDUINO_LIBRARY_Matter_SRCS
|
|||
libraries/Matter/src/MatterEndpoints/MatterDimmableLight.cpp
|
||||
libraries/Matter/src/MatterEndpoints/MatterColorTemperatureLight.cpp
|
||||
libraries/Matter/src/MatterEndpoints/MatterColorLight.cpp
|
||||
libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.cpp
|
||||
libraries/Matter/src/Matter.cpp)
|
||||
|
||||
set(ARDUINO_LIBRARY_PPP_SRCS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
// 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
|
||||
MatterEnhancedColorLight EnhancedColorLight;
|
||||
|
||||
// It will use HSV color to control all Matter Attribute Changes
|
||||
HsvColor_t currentHSVColor = {0, 0, 0};
|
||||
|
||||
// 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 Enhanced Color Light
|
||||
bool setLightState(bool state, espHsvColor_t colorHSV, uint8_t brighteness, uint16_t temperature_Mireds) {
|
||||
|
||||
if (state) {
|
||||
#ifdef RGB_BUILTIN
|
||||
// currentHSVColor keeps final color result
|
||||
espRgbColor_t rgbColor = espHsvColorToRgbColor(currentHSVColor);
|
||||
// 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, currentHSVColor.h << 16 | currentHSVColor.s << 8 | currentHSVColor.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 (21, 216, 25) - Warm White Color at 10% intensity
|
||||
uint32_t prefHsvColor = matterPref.getUInt(hsvColorPrefKey, 21 << 16 | 216 << 8 | 25);
|
||||
currentHSVColor = {uint8_t(prefHsvColor >> 16), uint8_t(prefHsvColor >> 8), uint8_t(prefHsvColor)};
|
||||
EnhancedColorLight.begin(lastOnOffState, currentHSVColor);
|
||||
// set the callback function to handle the Light state change
|
||||
EnhancedColorLight.onChange(setLightState);
|
||||
|
||||
// lambda functions are used to set the attribute change callbacks
|
||||
EnhancedColorLight.onChangeOnOff([](bool state) {
|
||||
Serial.printf("Light OnOff changed to %s\r\n", state ? "ON" : "OFF");
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeColorTemperature([](uint16_t colorTemperature) {
|
||||
Serial.printf("Light Color Temperature changed to %d\r\n", colorTemperature);
|
||||
// get correspondent Hue and Saturation of the color temperature
|
||||
HsvColor_t hsvTemperature = espRgbColorToHsvColor(espCTToRgbColor(colorTemperature));
|
||||
// keep previous the brightness and just change the Hue and Saturation
|
||||
currentHSVColor.h = hsvTemperature.h;
|
||||
currentHSVColor.s = hsvTemperature.s;
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeBrightness([](uint8_t brightness) {
|
||||
Serial.printf("Light brightness changed to %d\r\n", brightness);
|
||||
// change current brightness (HSV value)
|
||||
currentHSVColor.v = brightness;
|
||||
return true;
|
||||
});
|
||||
EnhancedColorLight.onChangeColorHSV([](HsvColor_t hsvColor) {
|
||||
Serial.printf("Light HSV Color changed to (%d,%d,%d)\r\n", hsvColor.h, hsvColor.s, hsvColor.v);
|
||||
// keep the current brightness and just change Hue and Saturation
|
||||
currentHSVColor.h = hsvColor.h;
|
||||
currentHSVColor.s = hsvColor.s;
|
||||
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", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r,
|
||||
EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
EnhancedColorLight.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", EnhancedColorLight ? "ON" : "OFF", EnhancedColorLight.getColorRGB().r,
|
||||
EnhancedColorLight.getColorRGB().g, EnhancedColorLight.getColorRGB().b
|
||||
);
|
||||
// configure the Light based on initial on-off state and its color
|
||||
EnhancedColorLight.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!");
|
||||
EnhancedColorLight.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.");
|
||||
EnhancedColorLight = false; // turn the light off
|
||||
Matter.decommission();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=huge_app",
|
||||
"requires": [
|
||||
"CONFIG_SOC_WIFI_SUPPORTED=y",
|
||||
"CONFIG_ESP_MATTER_ENABLE_DATA_MODEL=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ MatterOnOffLight KEYWORD1
|
|||
MatterDimmableLight KEYWORD1
|
||||
MatterColorTemperatureLight KEYWORD1
|
||||
MatterColorLight KEYWORD1
|
||||
MatterEnhancedColorLight KEYWORD1
|
||||
MatterEndPoint KEYWORD1
|
||||
|
||||
#######################################
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <MatterEndpoints/MatterDimmableLight.h>
|
||||
#include <MatterEndpoints/MatterColorTemperatureLight.h>
|
||||
#include <MatterEndpoints/MatterColorLight.h>
|
||||
#include <MatterEndpoints/MatterEnhancedColorLight.h>
|
||||
|
||||
using namespace esp_matter;
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ public:
|
|||
friend class MatterDimmableLight;
|
||||
friend class MatterColorTemperatureLight;
|
||||
friend class MatterColorLight;
|
||||
friend class MatterEnhancedColorLight;
|
||||
|
||||
protected:
|
||||
static void _init();
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public:
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,389 @@
|
|||
// 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/MatterEnhancedColorLight.h>
|
||||
|
||||
using namespace esp_matter;
|
||||
using namespace esp_matter::endpoint;
|
||||
using namespace chip::app::Clusters;
|
||||
|
||||
// endpoint for enhanced color light device
|
||||
namespace esp_matter {
|
||||
using namespace cluster;
|
||||
namespace endpoint {
|
||||
namespace enhanced_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() | color_control::feature::color_temperature::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 enhanced_color_light
|
||||
} // namespace endpoint
|
||||
} // namespace esp_matter
|
||||
|
||||
bool MatterEnhancedColorLight::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 Enhanced ColorLight device has not begun.");
|
||||
return false;
|
||||
}
|
||||
|
||||
log_d(
|
||||
"Enhanced ColorAttr 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("Enhanced ColorLight 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, brightnessLevel, colorTemperatureLevel);
|
||||
}
|
||||
if (ret == true) {
|
||||
onOffState = val->val.b;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LevelControl::Id:
|
||||
if (attribute_id == LevelControl::Attributes::CurrentLevel::Id) {
|
||||
log_d("Enhanced ColorLight Brightness changed to %d", val->val.u8);
|
||||
if (_onChangeBrightnessCB != NULL) {
|
||||
ret &= _onChangeBrightnessCB(val->val.u8);
|
||||
}
|
||||
if (_onChangeCB != NULL) {
|
||||
ret &= _onChangeCB(onOffState, colorHSV, val->val.u8, colorTemperatureLevel);
|
||||
}
|
||||
if (ret == true) {
|
||||
colorHSV.v = val->val.u8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ColorControl::Id:
|
||||
{
|
||||
if (attribute_id == ColorControl::Attributes::ColorTemperatureMireds::Id) {
|
||||
log_d("Enhanced ColorLight Temperature changed to %d", val->val.u16);
|
||||
if (_onChangeTemperatureCB != NULL) {
|
||||
ret &= _onChangeTemperatureCB(val->val.u16);
|
||||
}
|
||||
if (_onChangeCB != NULL) {
|
||||
ret &= _onChangeCB(onOffState, colorHSV, brightnessLevel, val->val.u16);
|
||||
}
|
||||
if (ret == true) {
|
||||
colorTemperatureLevel = val->val.u16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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("Enhanced ColorLight Hue changed to %d", val->val.u8);
|
||||
hsvColor.h = val->val.u8;
|
||||
} else { // attribute_id == ColorControl::Attributes::CurrentSaturation::Id)
|
||||
log_d("Enhanced ColorLight 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, brightnessLevel, colorTemperatureLevel);
|
||||
}
|
||||
if (ret == true) {
|
||||
colorHSV = {hsvColor.h, hsvColor.s, hsvColor.v};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MatterEnhancedColorLight::MatterEnhancedColorLight() {}
|
||||
|
||||
MatterEnhancedColorLight::~MatterEnhancedColorLight() {
|
||||
end();
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::begin(bool initialState, espHsvColor_t _colorHSV, uint8_t brightness, uint16_t ColorTemperature) {
|
||||
ArduinoMatter::_init();
|
||||
enhanced_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 = brightness;
|
||||
light_config.level_control.lighting.start_up_current_level = nullptr;
|
||||
|
||||
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;
|
||||
|
||||
light_config.color_control.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 = enhanced_color_light::create(node::get(), &light_config, ENDPOINT_FLAG_NONE, (void *)this);
|
||||
if (endpoint == nullptr) {
|
||||
log_e("Failed to create Enhanced ColorLight endpoint");
|
||||
return false;
|
||||
}
|
||||
|
||||
setEndPointId(endpoint::get_id(endpoint));
|
||||
log_i("Enhanced ColorLight 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 MatterEnhancedColorLight::end() {
|
||||
started = false;
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::setOnOff(bool newState) {
|
||||
if (!started) {
|
||||
log_e("Matter Enhanced ColorLight 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 MatterEnhancedColorLight::updateAccessory() {
|
||||
if (_onChangeCB != NULL) {
|
||||
_onChangeCB(onOffState, colorHSV, brightnessLevel, colorTemperatureLevel);
|
||||
}
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::getOnOff() {
|
||||
return onOffState;
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::toggle() {
|
||||
return setOnOff(!onOffState);
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::setBrightness(uint8_t newBrightness) {
|
||||
if (!started) {
|
||||
log_w("Matter Enhanced ColorLight 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 MatterEnhancedColorLight::getBrightness() {
|
||||
return brightnessLevel;
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::setColorTemperature(uint16_t newTemperature) {
|
||||
if (!started) {
|
||||
log_w("Matter Enhanced ColorLight 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 MatterEnhancedColorLight::getColorTemperature() {
|
||||
return colorTemperatureLevel;
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::setColorRGB(espRgbColor_t _rgbColor) {
|
||||
return setColorHSV(espRgbColorToHsvColor(_rgbColor));
|
||||
}
|
||||
|
||||
espRgbColor_t MatterEnhancedColorLight::getColorRGB() {
|
||||
return espHsvColorToRgbColor(colorHSV);
|
||||
}
|
||||
|
||||
bool MatterEnhancedColorLight::setColorHSV(espHsvColor_t _hsvColor) {
|
||||
|
||||
if (!started) {
|
||||
log_w("Matter Enhanced ColorLight 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 MatterEnhancedColorLight::getColorHSV() {
|
||||
return colorHSV;
|
||||
}
|
||||
|
||||
MatterEnhancedColorLight::operator bool() {
|
||||
return getOnOff();
|
||||
}
|
||||
|
||||
void MatterEnhancedColorLight::operator=(bool newState) {
|
||||
setOnOff(newState);
|
||||
}
|
||||
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||
102
libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.h
Normal file
102
libraries/Matter/src/MatterEndpoints/MatterEnhancedColorLight.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// 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 MatterEnhancedColorLight : 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;
|
||||
|
||||
MatterEnhancedColorLight();
|
||||
~MatterEnhancedColorLight();
|
||||
// default initial state is off, brightness = 25 (10%), HSV(21, 216, 25), color temperature is 454 (Warm White)
|
||||
virtual bool begin(bool initialState = false, espHsvColor_t colorHSV = {21, 216, 25}, uint8_t newBrightness = 25, uint16_t colorTemperature = 454);
|
||||
// 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 setColorTemperature(uint16_t newTemperature); // returns true if successful
|
||||
uint16_t getColorTemperature(); // returns current temperature
|
||||
|
||||
bool setBrightness(uint8_t newBrightness); // returns true if successful
|
||||
uint8_t getBrightness(); // returns current brightness
|
||||
|
||||
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 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 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 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, espHsvColor_t, 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)
|
||||
espHsvColor_t colorHSV = {0}; // default initial color HSV is black, but it can be changed by begin(bool, uint8_t, espHsvColor_t)
|
||||
uint16_t colorTemperatureLevel = 0; // default initial color temperature is 0, but it can be changed by begin(bool, uint8_t, espHsvColor_t, uint16_t)
|
||||
EndPointOnOffCB _onChangeOnOffCB = NULL;
|
||||
EndPointBrightnessCB _onChangeBrightnessCB = NULL;
|
||||
EndPointRGBColorCB _onChangeColorCB = NULL;
|
||||
EndPointTemperatureCB _onChangeTemperatureCB = NULL;
|
||||
EndPointCB _onChangeCB = NULL;
|
||||
};
|
||||
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||
Loading…
Reference in a new issue