RGBWW - added channel interlock for RGB vs white (#1042)

* Update light_color_values.h

* Update light_color_values.h

* Update light_color_values.h

* Update light_color_values.h

* colour relative to white value

* Update light_state.cpp

* Update light_state.cpp

* Update light_state.cpp

* Update light_state.cpp

* Update light_color_values.h

* Update light_state.cpp

* linting

* Update light_state.cpp

* Update light_color_values.h

* more lint

* more lint

* Update light_state.cpp

* Update light_state.cpp

* Update light_state.cpp

* add optional interlock

* Update test1.yaml

* Update light_state.cpp

* Update light_state.h

* interlock

* optional interlock.

* interlock as trait

* color interlock as trait

* optional color interlock....

* optional color interlock

* Update light_color_values.h

* Lint checks....

* making travis happy

* making sure gamma_correct fix is included

* Update light_color_values.h

* making travis happy

* clang-format

* Code tidy

* Update light_color_values.h

* Update light_color_values.h
This commit is contained in:
peq123 2020-07-10 00:29:44 +01:00 committed by GitHub
parent 33212d1abf
commit e5d4e12457
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 83 additions and 28 deletions

View file

@ -179,22 +179,28 @@ class LightColorValues {
}
/// Convert these light color values to an RGB representation and write them to red, green, blue.
void as_rgb(float *red, float *green, float *blue, float gamma = 0) const {
*red = gamma_correct(this->state_ * this->brightness_ * this->red_, gamma);
*green = gamma_correct(this->state_ * this->brightness_ * this->green_, gamma);
*blue = gamma_correct(this->state_ * this->brightness_ * this->blue_, gamma);
void as_rgb(float *red, float *green, float *blue, float gamma = 0, bool color_interlock = false) const {
float brightness = this->state_ * this->brightness_;
if (color_interlock) {
brightness = brightness * (1.0f - this->white_);
}
*red = gamma_correct(brightness * this->red_, gamma);
*green = gamma_correct(brightness * this->green_, gamma);
*blue = gamma_correct(brightness * this->blue_, gamma);
}
/// Convert these light color values to an RGBW representation and write them to red, green, blue, white.
void as_rgbw(float *red, float *green, float *blue, float *white, float gamma = 0) const {
this->as_rgb(red, green, blue, gamma);
void as_rgbw(float *red, float *green, float *blue, float *white, float gamma = 0,
bool color_interlock = false) const {
this->as_rgb(red, green, blue, gamma, color_interlock);
*white = gamma_correct(this->state_ * this->brightness_ * this->white_, gamma);
}
/// 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, float gamma = 0, bool constant_brightness = false) const {
this->as_rgb(red, green, blue, gamma);
float *cold_white, float *warm_white, float gamma = 0, bool constant_brightness = false,
bool color_interlock = false) const {
this->as_rgb(red, green, blue, gamma, color_interlock);
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;

View file

@ -400,26 +400,51 @@ LightColorValues LightCall::validate_() {
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
}
// make white values binary aka 0.0f or 1.0f...this allows brightness to do its job
if (traits.get_supports_color_interlock()) {
if (*this->white_ > 0.0f) {
this->white_ = optional<float>(1.0f);
} else {
this->white_ = optional<float>(0.0f);
}
}
}
// White to 0% if (exclusively) setting any RGB value
// White to 0% if (exclusively) setting any RGB value that isn't 255,255,255
else if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
if (!this->white_.has_value()) {
if (*this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f && traits.get_supports_rgb_white_value() &&
traits.get_supports_color_interlock()) {
this->white_ = optional<float>(1.0f);
} else if (!this->white_.has_value() || !traits.get_supports_rgb_white_value()) {
this->white_ = optional<float>(0.0f);
}
}
// if changing Kelvin alone, change to white light
else if (this->color_temperature_.has_value()) {
if (!this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
if (!traits.get_supports_color_interlock()) {
if (!this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
}
}
// if setting Kelvin 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;
bool now_white = *this->red_ == 1.0f && *this->blue_ == 1.0f && *this->green_ == 1.0f;
if (!this->white_.has_value() && was_color && now_white) {
this->white_ = optional<float>(1.0f);
if (traits.get_supports_color_interlock()) {
if (cv.get_white() < 1.0f) {
this->white_ = optional<float>(1.0f);
}
if (was_color && !this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
}
} else {
if (!this->white_.has_value() && was_color && now_white) {
this->white_ = optional<float>(1.0f);
}
}
}
@ -704,17 +729,20 @@ void LightState::current_values_as_binary(bool *binary) { this->current_values.a
void LightState::current_values_as_brightness(float *brightness) {
this->current_values.as_brightness(brightness, this->gamma_correct_);
}
void LightState::current_values_as_rgb(float *red, float *green, float *blue) {
this->current_values.as_rgb(red, green, blue, this->gamma_correct_);
void LightState::current_values_as_rgb(float *red, float *green, float *blue, bool color_interlock) {
auto traits = this->get_traits();
this->current_values.as_rgb(red, green, blue, this->gamma_correct_, traits.get_supports_color_interlock());
}
void LightState::current_values_as_rgbw(float *red, float *green, float *blue, float *white) {
this->current_values.as_rgbw(red, green, blue, white, this->gamma_correct_);
void LightState::current_values_as_rgbw(float *red, float *green, float *blue, float *white, bool color_interlock) {
auto traits = this->get_traits();
this->current_values.as_rgbw(red, green, blue, white, this->gamma_correct_, traits.get_supports_color_interlock());
}
void LightState::current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white,
bool constant_brightness) {
bool constant_brightness, bool color_interlock) {
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, this->gamma_correct_, constant_brightness);
warm_white, this->gamma_correct_, constant_brightness,
traits.get_supports_color_interlock());
}
void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness) {
auto traits = this->get_traits();

View file

@ -266,12 +266,12 @@ class LightState : public Nameable, public Component {
void current_values_as_brightness(float *brightness);
void current_values_as_rgb(float *red, float *green, float *blue);
void current_values_as_rgb(float *red, float *green, float *blue, bool color_interlock = false);
void current_values_as_rgbw(float *red, float *green, float *blue, float *white);
void current_values_as_rgbw(float *red, float *green, float *blue, float *white, bool color_interlock = false);
void current_values_as_rgbww(float *red, float *green, float *blue, float *cold_white, float *warm_white,
bool constant_brightness = false);
bool constant_brightness = false, bool color_interlock = false);
void current_values_as_cwww(float *cold_white, float *warm_white, bool constant_brightness = false);

View file

@ -20,6 +20,10 @@ class LightTraits {
void set_supports_color_temperature(bool supports_color_temperature) {
this->supports_color_temperature_ = supports_color_temperature;
}
bool get_supports_color_interlock() const { return this->supports_color_interlock_; }
void set_supports_color_interlock(bool supports_color_interlock) {
this->supports_color_interlock_ = supports_color_interlock;
}
float get_min_mireds() const { return this->min_mireds_; }
void set_min_mireds(float min_mireds) { this->min_mireds_ = min_mireds; }
float get_max_mireds() const { return this->max_mireds_; }
@ -32,6 +36,7 @@ class LightTraits {
bool supports_color_temperature_{false};
float min_mireds_{0};
float max_mireds_{0};
bool supports_color_interlock_{false};
};
} // namespace light

View file

@ -12,6 +12,7 @@ class RGBLightOutput : public light::LightOutput {
void set_red(output::FloatOutput *red) { red_ = red; }
void set_green(output::FloatOutput *green) { green_ = green; }
void set_blue(output::FloatOutput *blue) { blue_ = blue; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
@ -20,7 +21,7 @@ class RGBLightOutput : public light::LightOutput {
}
void write_state(light::LightState *state) override {
float red, green, blue;
state->current_values_as_rgb(&red, &green, &blue);
state->current_values_as_rgb(&red, &green, &blue, false);
this->red_->set_level(red);
this->green_->set_level(green);
this->blue_->set_level(blue);

View file

@ -5,6 +5,7 @@ from esphome.const import CONF_BLUE, CONF_GREEN, CONF_RED, CONF_OUTPUT_ID, CONF_
rgbw_ns = cg.esphome_ns.namespace('rgbw')
RGBWLightOutput = rgbw_ns.class_('RGBWLightOutput', light.LightOutput)
CONF_COLOR_INTERLOCK = 'color_interlock'
CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBWLightOutput),
@ -12,6 +13,7 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
cv.Required(CONF_GREEN): cv.use_id(output.FloatOutput),
cv.Required(CONF_BLUE): cv.use_id(output.FloatOutput),
cv.Required(CONF_WHITE): cv.use_id(output.FloatOutput),
cv.Optional(CONF_COLOR_INTERLOCK, default=False): cv.boolean,
})
@ -27,3 +29,4 @@ def to_code(config):
cg.add(var.set_blue(blue))
white = yield cg.get_variable(config[CONF_WHITE])
cg.add(var.set_white(white))
cg.add(var.set_color_interlock(config[CONF_COLOR_INTERLOCK]))

View file

@ -13,16 +13,18 @@ class RGBWLightOutput : public light::LightOutput {
void set_green(output::FloatOutput *green) { green_ = green; }
void set_blue(output::FloatOutput *blue) { blue_ = blue; }
void set_white(output::FloatOutput *white) { white_ = white; }
void set_color_interlock(bool color_interlock) { color_interlock_ = color_interlock; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
traits.set_supports_color_interlock(this->color_interlock_);
traits.set_supports_rgb(true);
traits.set_supports_rgb_white_value(true);
return traits;
}
void write_state(light::LightState *state) override {
float red, green, blue, white;
state->current_values_as_rgbw(&red, &green, &blue, &white);
state->current_values_as_rgbw(&red, &green, &blue, &white, this->color_interlock_);
this->red_->set_level(red);
this->green_->set_level(green);
this->blue_->set_level(blue);
@ -34,6 +36,7 @@ class RGBWLightOutput : public light::LightOutput {
output::FloatOutput *green_;
output::FloatOutput *blue_;
output::FloatOutput *white_;
bool color_interlock_{false};
};
} // namespace rgbw

View file

@ -9,6 +9,7 @@ rgbww_ns = cg.esphome_ns.namespace('rgbww')
RGBWWLightOutput = rgbww_ns.class_('RGBWWLightOutput', light.LightOutput)
CONF_CONSTANT_BRIGHTNESS = 'constant_brightness'
CONF_COLOR_INTERLOCK = 'color_interlock'
CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(RGBWWLightOutput),
@ -20,6 +21,7 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
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,
cv.Optional(CONF_COLOR_INTERLOCK, default=False): cv.boolean,
})
@ -42,3 +44,4 @@ def to_code(config):
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]))
cg.add(var.set_color_interlock(config[CONF_COLOR_INTERLOCK]))

View file

@ -17,19 +17,22 @@ class RGBWWLightOutput : public light::LightOutput {
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; }
void set_color_interlock(bool color_interlock) { color_interlock_ = color_interlock; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true);
traits.set_supports_rgb(true);
traits.set_supports_rgb_white_value(true);
traits.set_supports_color_temperature(true);
traits.set_supports_color_interlock(this->color_interlock_);
traits.set_min_mireds(this->cold_white_temperature_);
traits.set_max_mireds(this->warm_white_temperature_);
return traits;
}
void write_state(light::LightState *state) override {
float red, green, blue, cwhite, wwhite;
state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite, this->constant_brightness_);
state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite, this->constant_brightness_,
this->color_interlock_);
this->red_->set_level(red);
this->green_->set_level(green);
this->blue_->set_level(blue);
@ -46,6 +49,7 @@ class RGBWWLightOutput : public light::LightOutput {
float cold_white_temperature_;
float warm_white_temperature_;
bool constant_brightness_;
bool color_interlock_{false};
};
} // namespace rgbww

View file

@ -1114,6 +1114,7 @@ light:
green: pca_4
blue: pca_5
white: pca_6
color_interlock: true
- platform: rgbww
name: "Living Room Lights 2"
red: pca_3
@ -1123,6 +1124,7 @@ light:
warm_white: pca_6
cold_white_color_temperature: 153 mireds
warm_white_color_temperature: 500 mireds
color_interlock: true
- platform: cwww
name: "Living Room Lights 2"
cold_white: pca_6