From 8613c02d5c3e40938e39def1671fb37c69c9db11 Mon Sep 17 00:00:00 2001 From: kroimon Date: Wed, 8 Apr 2020 14:31:23 +0200 Subject: [PATCH] Add constant_brightness property to CWWW/RGBWW lights (#1007) Fixes https://github.com/esphome/feature-requests/issues/460 Co-authored-by: Otto Winter --- esphome/components/cwww/cwww_light_output.h | 4 ++- esphome/components/cwww/light.py | 4 +++ esphome/components/light/light_color_values.h | 25 +++++++++++++------ esphome/components/light/light_state.cpp | 10 +++++--- esphome/components/light/light_state.h | 5 ++-- esphome/components/rgbww/light.py | 4 +++ esphome/components/rgbww/rgbww_light_output.h | 4 ++- tests/test1.yaml | 1 + 8 files changed, 41 insertions(+), 16 deletions(-) diff --git a/esphome/components/cwww/cwww_light_output.h b/esphome/components/cwww/cwww_light_output.h index 8192039511..3351a98d24 100644 --- a/esphome/components/cwww/cwww_light_output.h +++ b/esphome/components/cwww/cwww_light_output.h @@ -13,6 +13,7 @@ class CWWWLightOutput : public light::LightOutput { void set_warm_white(output::FloatOutput *warm_white) { warm_white_ = warm_white; } void set_cold_white_temperature(float cold_white_temperature) { cold_white_temperature_ = cold_white_temperature; } void set_warm_white_temperature(float warm_white_temperature) { warm_white_temperature_ = warm_white_temperature; } + void set_constant_brightness(bool constant_brightness) { constant_brightness_ = constant_brightness; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); traits.set_supports_brightness(true); @@ -25,7 +26,7 @@ class CWWWLightOutput : public light::LightOutput { } void write_state(light::LightState *state) override { float cwhite, wwhite; - state->current_values_as_cwww(&cwhite, &wwhite); + state->current_values_as_cwww(&cwhite, &wwhite, this->constant_brightness_); this->cold_white_->set_level(cwhite); this->warm_white_->set_level(wwhite); } @@ -35,6 +36,7 @@ class CWWWLightOutput : public light::LightOutput { output::FloatOutput *warm_white_; float cold_white_temperature_; float warm_white_temperature_; + bool constant_brightness_; }; } // namespace cwww diff --git a/esphome/components/cwww/light.py b/esphome/components/cwww/light.py index f86f1eace0..5cc4262105 100644 --- a/esphome/components/cwww/light.py +++ b/esphome/components/cwww/light.py @@ -7,12 +7,15 @@ from esphome.const import CONF_OUTPUT_ID, CONF_COLD_WHITE, CONF_WARM_WHITE, \ cwww_ns = cg.esphome_ns.namespace('cwww') CWWWLightOutput = cwww_ns.class_('CWWWLightOutput', light.LightOutput) +CONF_CONSTANT_BRIGHTNESS = 'constant_brightness' + CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(CWWWLightOutput), cv.Required(CONF_COLD_WHITE): cv.use_id(output.FloatOutput), cv.Required(CONF_WARM_WHITE): cv.use_id(output.FloatOutput), cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature, cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature, + cv.Optional(CONF_CONSTANT_BRIGHTNESS, default=False): cv.boolean, }) @@ -26,3 +29,4 @@ def to_code(config): wwhite = yield cg.get_variable(config[CONF_WARM_WHITE]) cg.add(var.set_warm_white(wwhite)) cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) + cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) diff --git a/esphome/components/light/light_color_values.h b/esphome/components/light/light_color_values.h index 9ac8be1dd0..39a93cbbcd 100644 --- a/esphome/components/light/light_color_values.h +++ b/esphome/components/light/light_color_values.h @@ -190,24 +190,33 @@ class LightColorValues { /// Convert these light color values to an RGBWW representation with the given parameters. void as_rgbww(float color_temperature_cw, float color_temperature_ww, float *red, float *green, float *blue, - float *cold_white, float *warm_white) const { + float *cold_white, float *warm_white, bool constant_brightness = false) const { this->as_rgb(red, green, blue); const float color_temp = clamp(this->color_temperature_, color_temperature_cw, color_temperature_ww); const float ww_fraction = (color_temp - color_temperature_cw) / (color_temperature_ww - color_temperature_cw); const float cw_fraction = 1.0f - ww_fraction; - const float max_cw_ww = std::max(ww_fraction, cw_fraction); - *cold_white = this->state_ * this->brightness_ * this->white_ * (cw_fraction / max_cw_ww); - *warm_white = this->state_ * this->brightness_ * this->white_ * (ww_fraction / max_cw_ww); + *cold_white = this->state_ * this->brightness_ * this->white_ * cw_fraction; + *warm_white = this->state_ * this->brightness_ * this->white_ * ww_fraction; + if (!constant_brightness) { + const float max_cw_ww = std::max(ww_fraction, cw_fraction); + *cold_white /= max_cw_ww; + *warm_white /= max_cw_ww; + } } /// Convert these light color values to an CWWW representation with the given parameters. - void as_cwww(float color_temperature_cw, float color_temperature_ww, float *cold_white, float *warm_white) const { + void as_cwww(float color_temperature_cw, float color_temperature_ww, float *cold_white, float *warm_white, + bool constant_brightness = false) const { const float color_temp = clamp(this->color_temperature_, color_temperature_cw, color_temperature_ww); const float ww_fraction = (color_temp - color_temperature_cw) / (color_temperature_ww - color_temperature_cw); const float cw_fraction = 1.0f - ww_fraction; - const float max_cw_ww = std::max(ww_fraction, cw_fraction); - *cold_white = this->state_ * this->brightness_ * (cw_fraction / max_cw_ww); - *warm_white = this->state_ * this->brightness_ * (ww_fraction / max_cw_ww); + *cold_white = this->state_ * this->brightness_ * cw_fraction; + *warm_white = this->state_ * this->brightness_ * ww_fraction; + if (!constant_brightness) { + const float max_cw_ww = std::max(ww_fraction, cw_fraction); + *cold_white /= max_cw_ww; + *warm_white /= max_cw_ww; + } } /// Compare this LightColorValues to rhs, return true if and only if all attributes match. diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index 5e9166795e..c6e7df0811 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -718,19 +718,21 @@ void LightState::current_values_as_rgbw(float *red, float *green, float *blue, f *blue = gamma_correct(*blue, this->gamma_correct_); *white = gamma_correct(*white, this->gamma_correct_); } -void LightState::current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white) { +void LightState::current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white, + bool constant_brightness) { auto traits = this->get_traits(); this->current_values.as_rgbww(traits.get_min_mireds(), traits.get_max_mireds(), red, green, blue, cold_white, - warm_white); + warm_white, constant_brightness); *red = gamma_correct(*red, this->gamma_correct_); *green = gamma_correct(*green, this->gamma_correct_); *blue = gamma_correct(*blue, this->gamma_correct_); *cold_white = gamma_correct(*cold_white, this->gamma_correct_); *warm_white = gamma_correct(*warm_white, this->gamma_correct_); } -void LightState::current_values_as_cwww(float *cold_white, float *warm_white) { +void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness) { auto traits = this->get_traits(); - this->current_values.as_cwww(traits.get_min_mireds(), traits.get_max_mireds(), cold_white, warm_white); + this->current_values.as_cwww(traits.get_min_mireds(), traits.get_max_mireds(), cold_white, warm_white, + constant_brightness); *cold_white = gamma_correct(*cold_white, this->gamma_correct_); *warm_white = gamma_correct(*warm_white, this->gamma_correct_); } diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index 07a0e3147b..f399cc2be4 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -270,9 +270,10 @@ class LightState : public Nameable, public Component { void current_values_as_rgbw(float *red, float *green, float *blue, float *white); - void current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white); + void current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white, + bool constant_brightness = false); - void current_values_as_cwww(float *cold_white, float *warm_white); + void current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness = false); protected: friend LightOutput; diff --git a/esphome/components/rgbww/light.py b/esphome/components/rgbww/light.py index c804eed942..78f4bee630 100644 --- a/esphome/components/rgbww/light.py +++ b/esphome/components/rgbww/light.py @@ -8,6 +8,8 @@ from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_OUTPUT_ID, CONF_ rgbww_ns = cg.esphome_ns.namespace('rgbww') RGBWWLightOutput = rgbww_ns.class_('RGBWWLightOutput', light.LightOutput) +CONF_CONSTANT_BRIGHTNESS = 'constant_brightness' + CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({ cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBWWLightOutput), cv.Required(CONF_RED): cv.use_id(output.FloatOutput), @@ -17,6 +19,7 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({ cv.Required(CONF_WARM_WHITE): cv.use_id(output.FloatOutput), cv.Required(CONF_COLD_WHITE_COLOR_TEMPERATURE): cv.color_temperature, cv.Required(CONF_WARM_WHITE_COLOR_TEMPERATURE): cv.color_temperature, + cv.Optional(CONF_CONSTANT_BRIGHTNESS, default=False): cv.boolean, }) @@ -38,3 +41,4 @@ def to_code(config): wwhite = yield cg.get_variable(config[CONF_WARM_WHITE]) cg.add(var.set_warm_white(wwhite)) cg.add(var.set_warm_white_temperature(config[CONF_WARM_WHITE_COLOR_TEMPERATURE])) + cg.add(var.set_constant_brightness(config[CONF_CONSTANT_BRIGHTNESS])) diff --git a/esphome/components/rgbww/rgbww_light_output.h b/esphome/components/rgbww/rgbww_light_output.h index ef9e99a3eb..a975331a37 100644 --- a/esphome/components/rgbww/rgbww_light_output.h +++ b/esphome/components/rgbww/rgbww_light_output.h @@ -16,6 +16,7 @@ class RGBWWLightOutput : public light::LightOutput { void set_warm_white(output::FloatOutput *warm_white) { warm_white_ = warm_white; } void set_cold_white_temperature(float cold_white_temperature) { cold_white_temperature_ = cold_white_temperature; } void set_warm_white_temperature(float warm_white_temperature) { warm_white_temperature_ = warm_white_temperature; } + void set_constant_brightness(bool constant_brightness) { constant_brightness_ = constant_brightness; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); traits.set_supports_brightness(true); @@ -28,7 +29,7 @@ class RGBWWLightOutput : public light::LightOutput { } void write_state(light::LightState *state) override { float red, green, blue, cwhite, wwhite; - state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite); + state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite, this->constant_brightness_); this->red_->set_level(red); this->green_->set_level(green); this->blue_->set_level(blue); @@ -44,6 +45,7 @@ class RGBWWLightOutput : public light::LightOutput { output::FloatOutput *warm_white_; float cold_white_temperature_; float warm_white_temperature_; + bool constant_brightness_; }; } // namespace rgbww diff --git a/tests/test1.yaml b/tests/test1.yaml index f87d77c9c2..8483281b59 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1074,6 +1074,7 @@ light: warm_white: pca_6 cold_white_color_temperature: 153 mireds warm_white_color_temperature: 500 mireds + constant_brightness: true - platform: fastled_clockless id: addr1 chipset: WS2811