1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-15 01:32:19 +01:00

Color mode implementation (#2012)

This commit is contained in:
Oxan van Leeuwen
2021-07-29 19:11:56 +02:00
committed by GitHub
parent de382b704c
commit 5983ccc55c
39 changed files with 1210 additions and 476 deletions

View File

@@ -7,95 +7,42 @@ namespace light {
static const char *const TAG = "light";
#ifdef USE_JSON
LightCall &LightCall::parse_color_json(JsonObject &root) {
if (root.containsKey("state")) {
auto val = parse_on_off(root["state"]);
switch (val) {
case PARSE_ON:
this->set_state(true);
break;
case PARSE_OFF:
this->set_state(false);
break;
case PARSE_TOGGLE:
this->set_state(!this->parent_->remote_values.is_on());
break;
case PARSE_NONE:
break;
}
static const char *color_mode_to_human(ColorMode color_mode) {
switch (color_mode) {
case ColorMode::UNKNOWN:
return "Unknown";
case ColorMode::WHITE:
return "White";
case ColorMode::COLOR_TEMPERATURE:
return "Color temperature";
case ColorMode::COLD_WARM_WHITE:
return "Cold/warm white";
case ColorMode::RGB:
return "RGB";
case ColorMode::RGB_WHITE:
return "RGBW";
case ColorMode::RGB_COLD_WARM_WHITE:
return "RGB + cold/warm white";
case ColorMode::RGB_COLOR_TEMPERATURE:
return "RGB + color temperature";
default:
return "";
}
if (root.containsKey("brightness")) {
this->set_brightness(float(root["brightness"]) / 255.0f);
}
if (root.containsKey("color")) {
JsonObject &color = root["color"];
// HA also encodes brightness information in the r, g, b values, so extract that and set it as color brightness.
float max_rgb = 0.0f;
if (color.containsKey("r")) {
float r = float(color["r"]) / 255.0f;
max_rgb = fmaxf(max_rgb, r);
this->set_red(r);
}
if (color.containsKey("g")) {
float g = float(color["g"]) / 255.0f;
max_rgb = fmaxf(max_rgb, g);
this->set_green(g);
}
if (color.containsKey("b")) {
float b = float(color["b"]) / 255.0f;
max_rgb = fmaxf(max_rgb, b);
this->set_blue(b);
}
if (color.containsKey("r") || color.containsKey("g") || color.containsKey("b")) {
this->set_color_brightness(max_rgb);
}
}
if (root.containsKey("white_value")) {
this->set_white(float(root["white_value"]) / 255.0f);
}
if (root.containsKey("color_temp")) {
this->set_color_temperature(float(root["color_temp"]));
}
return *this;
}
LightCall &LightCall::parse_json(JsonObject &root) {
this->parse_color_json(root);
if (root.containsKey("flash")) {
auto length = uint32_t(float(root["flash"]) * 1000);
this->set_flash_length(length);
}
if (root.containsKey("transition")) {
auto length = uint32_t(float(root["transition"]) * 1000);
this->set_transition_length(length);
}
if (root.containsKey("effect")) {
const char *effect = root["effect"];
this->set_effect(effect);
}
return *this;
}
#endif
void LightCall::perform() {
// use remote values for fallback
const char *name = this->parent_->get_name().c_str();
if (this->publish_) {
ESP_LOGD(TAG, "'%s' Setting:", name);
}
LightColorValues v = this->validate_();
if (this->publish_) {
ESP_LOGD(TAG, "'%s' Setting:", name);
// Only print color mode when it's being changed
ColorMode current_color_mode = this->parent_->remote_values.get_color_mode();
if (this->color_mode_.value_or(current_color_mode) != current_color_mode) {
ESP_LOGD(TAG, " Color mode: %s", color_mode_to_human(v.get_color_mode()));
}
// Only print state when it's being changed
bool current_state = this->parent_->remote_values.is_on();
if (this->state_.value_or(current_state) != current_state) {
@@ -106,30 +53,35 @@ void LightCall::perform() {
ESP_LOGD(TAG, " Brightness: %.0f%%", v.get_brightness() * 100.0f);
}
if (this->color_temperature_.has_value()) {
ESP_LOGD(TAG, " Color Temperature: %.1f mireds", v.get_color_temperature());
}
if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
ESP_LOGD(TAG, " Red=%.0f%%, Green=%.0f%%, Blue=%.0f%%", v.get_red() * 100.0f, v.get_green() * 100.0f,
ESP_LOGD(TAG, " Red: %.0f%%, Green: %.0f%%, Blue: %.0f%%", v.get_red() * 100.0f, v.get_green() * 100.0f,
v.get_blue() * 100.0f);
}
if (this->white_.has_value()) {
ESP_LOGD(TAG, " White Value: %.0f%%", v.get_white() * 100.0f);
ESP_LOGD(TAG, " White: %.0f%%", v.get_white() * 100.0f);
}
if (this->color_temperature_.has_value()) {
ESP_LOGD(TAG, " Color temperature: %.1f mireds", v.get_color_temperature());
}
if (this->cold_white_.has_value() || this->warm_white_.has_value()) {
ESP_LOGD(TAG, " Cold white: %.0f%%, warm white: %.0f%%", v.get_cold_white() * 100.0f,
v.get_warm_white() * 100.0f);
}
}
if (this->has_flash_()) {
// FLASH
if (this->publish_) {
ESP_LOGD(TAG, " Flash Length: %.1fs", *this->flash_length_ / 1e3f);
ESP_LOGD(TAG, " Flash length: %.1fs", *this->flash_length_ / 1e3f);
}
this->parent_->start_flash_(v, *this->flash_length_);
} else if (this->has_transition_()) {
// TRANSITION
if (this->publish_) {
ESP_LOGD(TAG, " Transition Length: %.1fs", *this->transition_length_ / 1e3f);
ESP_LOGD(TAG, " Transition length: %.1fs", *this->transition_length_ / 1e3f);
}
// Special case: Transition and effect can be set when turning off
@@ -177,32 +129,48 @@ void LightCall::perform() {
}
LightColorValues LightCall::validate_() {
// use remote values for fallback
auto *name = this->parent_->get_name().c_str();
auto traits = this->parent_->get_traits();
// Color mode check
if (this->color_mode_.has_value() && !traits.supports_color_mode(this->color_mode_.value())) {
ESP_LOGW(TAG, "'%s' - This light does not support color mode %s!", name,
color_mode_to_human(this->color_mode_.value()));
this->color_mode_.reset();
}
// Ensure there is always a color mode set
if (!this->color_mode_.has_value()) {
this->color_mode_ = this->compute_color_mode_();
}
auto color_mode = *this->color_mode_;
// Transform calls that use non-native parameters for the current mode.
this->transform_parameters_();
// Brightness exists check
if (this->brightness_.has_value() && !traits.get_supports_brightness()) {
if (this->brightness_.has_value() && !(color_mode & ColorCapability::BRIGHTNESS)) {
ESP_LOGW(TAG, "'%s' - This light does not support setting brightness!", name);
this->brightness_.reset();
}
// Transition length possible check
if (this->transition_length_.has_value() && *this->transition_length_ != 0 && !traits.get_supports_brightness()) {
if (this->transition_length_.has_value() && *this->transition_length_ != 0 &&
!(color_mode & ColorCapability::BRIGHTNESS)) {
ESP_LOGW(TAG, "'%s' - This light does not support transitions!", name);
this->transition_length_.reset();
}
// Color brightness exists check
if (this->color_brightness_.has_value() && !traits.get_supports_rgb()) {
ESP_LOGW(TAG, "'%s' - This light does not support setting RGB brightness!", name);
if (this->color_brightness_.has_value() && !(color_mode & ColorCapability::RGB)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting RGB brightness!", name);
this->color_brightness_.reset();
}
// RGB exists check
if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
if (!traits.get_supports_rgb()) {
ESP_LOGW(TAG, "'%s' - This light does not support setting RGB color!", name);
if (!(color_mode & ColorCapability::RGB)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting RGB color!", name);
this->red_.reset();
this->green_.reset();
this->blue_.reset();
@@ -210,68 +178,25 @@ LightColorValues LightCall::validate_() {
}
// White value exists check
if (this->white_.has_value() && !traits.get_supports_rgb_white_value()) {
ESP_LOGW(TAG, "'%s' - This light does not support setting white value!", name);
if (this->white_.has_value() &&
!(color_mode & ColorCapability::WHITE || color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting white value!", name);
this->white_.reset();
}
// Color temperature exists check
if (this->color_temperature_.has_value() && !traits.get_supports_color_temperature()) {
ESP_LOGW(TAG, "'%s' - This light does not support setting color temperature!", name);
if (this->color_temperature_.has_value() &&
!(color_mode & ColorCapability::COLOR_TEMPERATURE || color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting color temperature!", name);
this->color_temperature_.reset();
}
// Set color brightness to 100% if currently zero and a color is set. This is both for compatibility with older
// clients that don't know about color brightness, and it's intuitive UX anyway: if I set a color, it should show up.
if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
if (!this->color_brightness_.has_value() && this->parent_->remote_values.get_color_brightness() == 0.0f)
this->color_brightness_ = optional<float>(1.0f);
}
// Handle interaction between RGB and white for color interlock
if (traits.get_supports_color_interlock()) {
// Find out which channel (white or color) the user wanted to enable
bool output_white = this->white_.has_value() && *this->white_ > 0.0f;
bool output_color = (this->color_brightness_.has_value() && *this->color_brightness_ > 0.0f) ||
this->red_.has_value() || this->green_.has_value() || this->blue_.has_value();
// Interpret setting the color to white as setting the white channel.
if (output_color && *this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f) {
output_white = true;
output_color = false;
if (!this->white_.has_value())
this->white_ = optional<float>(this->color_brightness_.value_or(1.0f));
}
// Ensure either the white value or the color brightness is always zero.
if (output_white && output_color) {
ESP_LOGW(TAG, "'%s' - Cannot enable color and white channel simultaneously with interlock!", name);
// For compatibility with historic behaviour, prefer white channel in this case.
this->color_brightness_ = optional<float>(0.0f);
} else if (output_white) {
this->color_brightness_ = optional<float>(0.0f);
} else if (output_color) {
this->white_ = optional<float>(0.0f);
}
}
// If only a color temperature is specified, change to white light
if (this->color_temperature_.has_value() && !this->white_.has_value() && !this->red_.has_value() &&
!this->green_.has_value() && !this->blue_.has_value()) {
// Disable color LEDs explicitly if not already set
if (traits.get_supports_rgb() && !this->color_brightness_.has_value())
this->color_brightness_ = optional<float>(0.0f);
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
// if setting color temperature from color (i.e. switching to white light), set White to 100%
auto cv = this->parent_->remote_values;
bool was_color = cv.get_red() != 1.0f || cv.get_blue() != 1.0f || cv.get_green() != 1.0f;
if (traits.get_supports_color_interlock() || was_color) {
this->white_ = optional<float>(1.0f);
// Cold/warm white value exists check
if (this->cold_white_.has_value() || this->warm_white_.has_value()) {
if (!(color_mode & ColorCapability::COLD_WARM_WHITE)) {
ESP_LOGW(TAG, "'%s' - This color mode does not support setting cold/warm white value!", name);
this->cold_white_.reset();
this->warm_white_.reset();
}
}
@@ -292,13 +217,22 @@ LightColorValues LightCall::validate_() {
VALIDATE_RANGE(green, "Green")
VALIDATE_RANGE(blue, "Blue")
VALIDATE_RANGE(white, "White")
VALIDATE_RANGE(cold_white, "Cold white")
VALIDATE_RANGE(warm_white, "Warm white")
// Set color brightness to 100% if currently zero and a color is set.
if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
if (!this->color_brightness_.has_value() && this->parent_->remote_values.get_color_brightness() == 0.0f)
this->color_brightness_ = optional<float>(1.0f);
}
auto v = this->parent_->remote_values;
if (this->color_mode_.has_value())
v.set_color_mode(*this->color_mode_);
if (this->state_.has_value())
v.set_state(*this->state_);
if (this->brightness_.has_value())
v.set_brightness(*this->brightness_);
if (this->color_brightness_.has_value())
v.set_color_brightness(*this->color_brightness_);
if (this->red_.has_value())
@@ -309,9 +243,12 @@ LightColorValues LightCall::validate_() {
v.set_blue(*this->blue_);
if (this->white_.has_value())
v.set_white(*this->white_);
if (this->color_temperature_.has_value())
v.set_color_temperature(*this->color_temperature_);
if (this->cold_white_.has_value())
v.set_cold_white(*this->cold_white_);
if (this->warm_white_.has_value())
v.set_warm_white(*this->warm_white_);
v.normalize_color(traits);
@@ -322,7 +259,7 @@ LightColorValues LightCall::validate_() {
}
// validate transition length/flash length/effect not used at the same time
bool supports_transition = traits.get_supports_brightness();
bool supports_transition = color_mode & ColorCapability::BRIGHTNESS;
// If effect is already active, remove effect start
if (this->has_effect_() && *this->effect_ == this->parent_->active_effect_index_) {
@@ -331,7 +268,7 @@ LightColorValues LightCall::validate_() {
// validate effect index
if (this->has_effect_() && *this->effect_ > this->parent_->effects_.size()) {
ESP_LOGW(TAG, "'%s' Invalid effect index %u", name, *this->effect_);
ESP_LOGW(TAG, "'%s' - Invalid effect index %u!", name, *this->effect_);
this->effect_.reset();
}
@@ -381,6 +318,127 @@ LightColorValues LightCall::validate_() {
return v;
}
void LightCall::transform_parameters_() {
auto traits = this->parent_->get_traits();
// Allow CWWW modes to be set with a white value and/or color temperature. This is used by HA,
// which doesn't support CWWW modes (yet?), and for compatibility with the pre-colormode model,
// as CWWW and RGBWW lights used to represent their values as white + color temperature.
if (((this->white_.has_value() && *this->white_ > 0.0f) || this->color_temperature_.has_value()) && //
(*this->color_mode_ & ColorCapability::COLD_WARM_WHITE) && //
!(*this->color_mode_ & ColorCapability::WHITE) && //
!(*this->color_mode_ & ColorCapability::COLOR_TEMPERATURE) && //
traits.get_min_mireds() > 0.0f && traits.get_max_mireds() > 0.0f) {
ESP_LOGD(TAG, "'%s' - Setting cold/warm white channels using white/color temperature values.",
this->parent_->get_name().c_str());
auto current_values = this->parent_->remote_values;
if (this->color_temperature_.has_value()) {
const float white =
this->white_.value_or(fmaxf(current_values.get_cold_white(), current_values.get_warm_white()));
const float color_temp = clamp(*this->color_temperature_, traits.get_min_mireds(), traits.get_max_mireds());
const float ww_fraction =
(color_temp - traits.get_min_mireds()) / (traits.get_max_mireds() - traits.get_min_mireds());
const float cw_fraction = 1.0f - ww_fraction;
const float max_cw_ww = std::max(ww_fraction, cw_fraction);
this->cold_white_ = white * gamma_uncorrect(cw_fraction / max_cw_ww, this->parent_->get_gamma_correct());
this->warm_white_ = white * gamma_uncorrect(ww_fraction / max_cw_ww, this->parent_->get_gamma_correct());
} else {
const float max_cw_ww = std::max(current_values.get_warm_white(), current_values.get_cold_white());
this->cold_white_ = *this->white_ * current_values.get_cold_white() / max_cw_ww;
this->warm_white_ = *this->white_ * current_values.get_warm_white() / max_cw_ww;
}
}
}
ColorMode LightCall::compute_color_mode_() {
auto supported_modes = this->parent_->get_traits().get_supported_color_modes();
int supported_count = supported_modes.size();
// Some lights don't support any color modes (e.g. monochromatic light), leave it at unknown.
if (supported_count == 0)
return ColorMode::UNKNOWN;
// In the common case of lights supporting only a single mode, use that one.
if (supported_count == 1)
return *supported_modes.begin();
// Don't change if the light is being turned off.
ColorMode current_mode = this->parent_->remote_values.get_color_mode();
if (this->state_.has_value() && !*this->state_)
return current_mode;
// If no color mode is specified, we try to guess the color mode. This is needed for backward compatibility to
// pre-colormode clients and automations, but also for the MQTT API, where HA doesn't let us know which color mode
// was used for some reason.
std::set<ColorMode> suitable_modes = this->get_suitable_color_modes_();
// Don't change if the current mode is suitable.
if (suitable_modes.count(current_mode) > 0) {
ESP_LOGI(TAG, "'%s' - Keeping current color mode %s for call without color mode.",
this->parent_->get_name().c_str(), color_mode_to_human(current_mode));
return current_mode;
}
// Use the preferred suitable mode.
for (auto mode : suitable_modes) {
if (supported_modes.count(mode) == 0)
continue;
ESP_LOGI(TAG, "'%s' - Using color mode %s for call without color mode.", this->parent_->get_name().c_str(),
color_mode_to_human(mode));
return mode;
}
// There's no supported mode for this call, so warn, use the current more or a mode at random and let validation strip
// out whatever we don't support.
auto color_mode = current_mode != ColorMode::UNKNOWN ? current_mode : *supported_modes.begin();
ESP_LOGW(TAG, "'%s' - No color mode suitable for this call supported, defaulting to %s!",
this->parent_->get_name().c_str(), color_mode_to_human(color_mode));
return color_mode;
}
std::set<ColorMode> LightCall::get_suitable_color_modes_() {
bool has_white = this->white_.has_value() && *this->white_ > 0.0f;
bool has_ct = this->color_temperature_.has_value();
bool has_cwww = (this->cold_white_.has_value() && *this->cold_white_ > 0.0f) ||
(this->warm_white_.has_value() && *this->warm_white_ > 0.0f);
bool has_rgb = (this->color_brightness_.has_value() && *this->color_brightness_ > 0.0f) ||
(this->red_.has_value() || this->green_.has_value() || this->blue_.has_value());
#define KEY(white, ct, cwww, rgb) ((white) << 0 | (ct) << 1 | (cwww) << 2 | (rgb) << 3)
#define ENTRY(white, ct, cwww, rgb, ...) \
std::make_tuple<uint8_t, std::set<ColorMode>>(KEY(white, ct, cwww, rgb), __VA_ARGS__)
// Flag order: white, color temperature, cwww, rgb
std::array<std::tuple<uint8_t, std::set<ColorMode>>, 10> lookup_table{
ENTRY(true, false, false, false,
{ColorMode::WHITE, ColorMode::RGB_WHITE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::COLD_WARM_WHITE,
ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, true, false, false,
{ColorMode::COLOR_TEMPERATURE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::COLD_WARM_WHITE,
ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(true, true, false, false,
{ColorMode::COLD_WARM_WHITE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, false, true, false, {ColorMode::COLD_WARM_WHITE, ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, false, false, false,
{ColorMode::RGB_WHITE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE, ColorMode::RGB,
ColorMode::WHITE, ColorMode::COLOR_TEMPERATURE, ColorMode::COLD_WARM_WHITE}),
ENTRY(true, false, false, true,
{ColorMode::RGB_WHITE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, true, false, true, {ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(true, true, false, true, {ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, false, true, true, {ColorMode::RGB_COLD_WARM_WHITE}),
ENTRY(false, false, false, true,
{ColorMode::RGB, ColorMode::RGB_WHITE, ColorMode::RGB_COLOR_TEMPERATURE, ColorMode::RGB_COLD_WARM_WHITE}),
};
auto key = KEY(has_white, has_ct, has_cwww, has_rgb);
for (auto &item : lookup_table)
if (std::get<0>(item) == key)
return std::get<1>(item);
// This happens if there are conflicting flags given.
return {};
}
LightCall &LightCall::set_effect(const std::string &effect) {
if (strcasecmp(effect.c_str(), "none") == 0) {
this->set_effect(0);
@@ -406,53 +464,74 @@ LightCall &LightCall::from_light_color_values(const LightColorValues &values) {
this->set_state(values.is_on());
this->set_brightness_if_supported(values.get_brightness());
this->set_color_brightness_if_supported(values.get_color_brightness());
this->set_color_mode_if_supported(values.get_color_mode());
this->set_red_if_supported(values.get_red());
this->set_green_if_supported(values.get_green());
this->set_blue_if_supported(values.get_blue());
this->set_white_if_supported(values.get_white());
this->set_color_temperature_if_supported(values.get_color_temperature());
this->set_cold_white_if_supported(values.get_cold_white());
this->set_warm_white_if_supported(values.get_warm_white());
return *this;
}
ColorMode LightCall::get_active_color_mode_() {
return this->color_mode_.value_or(this->parent_->remote_values.get_color_mode());
}
LightCall &LightCall::set_transition_length_if_supported(uint32_t transition_length) {
if (this->parent_->get_traits().get_supports_brightness())
if (this->get_active_color_mode_() & ColorCapability::BRIGHTNESS)
this->set_transition_length(transition_length);
return *this;
}
LightCall &LightCall::set_brightness_if_supported(float brightness) {
if (this->parent_->get_traits().get_supports_brightness())
if (this->get_active_color_mode_() & ColorCapability::BRIGHTNESS)
this->set_brightness(brightness);
return *this;
}
LightCall &LightCall::set_color_mode_if_supported(ColorMode color_mode) {
if (this->parent_->get_traits().supports_color_mode(color_mode))
this->color_mode_ = color_mode;
return *this;
}
LightCall &LightCall::set_color_brightness_if_supported(float brightness) {
if (this->parent_->get_traits().get_supports_rgb_white_value())
if (this->get_active_color_mode_() & ColorCapability::RGB)
this->set_color_brightness(brightness);
return *this;
}
LightCall &LightCall::set_red_if_supported(float red) {
if (this->parent_->get_traits().get_supports_rgb())
if (this->get_active_color_mode_() & ColorCapability::RGB)
this->set_red(red);
return *this;
}
LightCall &LightCall::set_green_if_supported(float green) {
if (this->parent_->get_traits().get_supports_rgb())
if (this->get_active_color_mode_() & ColorCapability::RGB)
this->set_green(green);
return *this;
}
LightCall &LightCall::set_blue_if_supported(float blue) {
if (this->parent_->get_traits().get_supports_rgb())
if (this->get_active_color_mode_() & ColorCapability::RGB)
this->set_blue(blue);
return *this;
}
LightCall &LightCall::set_white_if_supported(float white) {
if (this->parent_->get_traits().get_supports_rgb_white_value())
if (this->get_active_color_mode_() & ColorCapability::WHITE)
this->set_white(white);
return *this;
}
LightCall &LightCall::set_color_temperature_if_supported(float color_temperature) {
if (this->parent_->get_traits().get_supports_color_temperature())
if (this->get_active_color_mode_() & ColorCapability::COLOR_TEMPERATURE)
this->set_color_temperature(color_temperature);
return *this;
}
LightCall &LightCall::set_cold_white_if_supported(float cold_white) {
if (this->get_active_color_mode_() & ColorCapability::COLD_WARM_WHITE)
this->set_cold_white(cold_white);
return *this;
}
LightCall &LightCall::set_warm_white_if_supported(float warm_white) {
if (this->get_active_color_mode_() & ColorCapability::COLD_WARM_WHITE)
this->set_warm_white(warm_white);
return *this;
}
LightCall &LightCall::set_state(optional<bool> state) {
this->state_ = state;
return *this;
@@ -485,6 +564,14 @@ LightCall &LightCall::set_brightness(float brightness) {
this->brightness_ = brightness;
return *this;
}
LightCall &LightCall::set_color_mode(optional<ColorMode> color_mode) {
this->color_mode_ = color_mode;
return *this;
}
LightCall &LightCall::set_color_mode(ColorMode color_mode) {
this->color_mode_ = color_mode;
return *this;
}
LightCall &LightCall::set_color_brightness(optional<float> brightness) {
this->color_brightness_ = brightness;
return *this;
@@ -533,6 +620,22 @@ LightCall &LightCall::set_color_temperature(float color_temperature) {
this->color_temperature_ = color_temperature;
return *this;
}
LightCall &LightCall::set_cold_white(optional<float> cold_white) {
this->cold_white_ = cold_white;
return *this;
}
LightCall &LightCall::set_cold_white(float cold_white) {
this->cold_white_ = cold_white;
return *this;
}
LightCall &LightCall::set_warm_white(optional<float> warm_white) {
this->warm_white_ = warm_white;
return *this;
}
LightCall &LightCall::set_warm_white(float warm_white) {
this->warm_white_ = warm_white;
return *this;
}
LightCall &LightCall::set_effect(optional<std::string> effect) {
if (effect.has_value())
this->set_effect(*effect);