Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ESPHome Custom RGBW Light with emulated warm/cool white
#include "esphome.h"
class FrankeverCustomLight : public Component, public LightOutput {
public:
FrankeverCustomLight(FloatOutput *red, FloatOutput *green, FloatOutput *blue, FloatOutput *white)
{
red_ = red;
green_ = green;
blue_ = blue;
white_ = white;
}
LightTraits get_traits() override {
auto traits = LightTraits();
traits.set_supports_brightness(true);
traits.set_supports_rgb(true);
traits.set_supports_rgb_white_value(false);
traits.set_supports_color_temperature(true);
traits.set_min_mireds(153); // home assistant minimum 153
traits.set_max_mireds(500); // home assistant maximum 500
// medium is 326.5
return traits;
}
void write_state(LightState *state) override {
float red, green, blue, cwhite, wwhite, colourTemp;
state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite);
colourTemp = state->current_values.get_color_temperature();
// TODO at the moment the lights boot up with cool temperature, can we default to warm?
float coolToWarmThreshold = (colourTemp - 153) / (500 - 153);
// slowly fade in white LED and fade out colour LEDs
float whitePart = std::min(red, std::min(green, blue));
float redPart = red - whitePart;
float greenPart = green - whitePart;
float bluePart = blue - whitePart;
float whiteLightMultiplier = std::min(coolToWarmThreshold * 2.25f, 1.0f); // half way point is full white light, so turn 0.5 -> 1
float colourLightMultiplier = std::max(-(coolToWarmThreshold * 2.25f - 1.0f), 0.0f);
float extraRedMultiplier = whitePart * std::max(0.0f, std::min((coolToWarmThreshold - 0.6f) * 2.0f, 1.0f)); // beyond half way is extra warm red
float newWhite = whitePart * whiteLightMultiplier;
float newRed = (colourLightMultiplier * (red - redPart)) + redPart;
float newGreen = (colourLightMultiplier * (green - greenPart)) + greenPart;
float newBlue = (colourLightMultiplier * (blue - bluePart)) + bluePart;
float newRedWithExtraRed = (extraRedMultiplier * (1 - newRed)) + newRed;
// ESP_LOGD("custom",
// "colourTemp %f, whitepart %f redpart %f greenpart %f bluepart %f whitemulti %f colourmulti %f extramulti %f newwhite %f newred %f newgreen %f newblue %f newnewred %f",
// colourTemp, whitePart, redPart, greenPart, bluePart, whiteLightMultiplier, colourLightMultiplier, extraRedMultiplier, newWhite, newRed, newGreen, newBlue, newRedWithExtraRed);
this->red_->set_level(newRedWithExtraRed);
this->green_->set_level(newGreen);
this->blue_->set_level(newBlue);
this->white_->set_level(newWhite);
}
protected:
FloatOutput *red_;
FloatOutput *green_;
FloatOutput *blue_;
FloatOutput *white_;
};
esphome:
includes:
- frankeverCustomLight.h
output:
- platform: my9231
id: output_red
channel: 3
- platform: my9231
id: output_green
channel: 2
- platform: my9231
id: output_blue
channel: 1
- platform: my9231
id: output_white
channel: 0
light:
- platform: custom
lambda: |-
auto light_out = new FrankeverCustomLight(id(output_red), id(output_green), id(output_blue), id(output_white));
App.register_component(light_out);
return {light_out};
lights:
- name: "${friendly_name}"
default_transition_length: 0.1s
restore_mode: ALWAYS_OFF # because powercut could then cause all lights to turn on
effects:
- random:
- strobe:
- flicker:
@triphoppingman

This comment has been minimized.

Copy link

triphoppingman commented Nov 22, 2019

Jamie:

I have made some changes to your code: https://gist.github.com/triphoppingman/76153ddf58072b10e229e9147b2bdf72

This maps the color temp to the RGBW values using a set of linear equations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.