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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user