Skip to content

Instantly share code, notes, and snippets.

@vandarin
Forked from triphoppingman/ColorTempRGBWLight.h
Last active August 21, 2023 22:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vandarin/5782958e9eca16b3caf4c7742e8d9d24 to your computer and use it in GitHub Desktop.
Save vandarin/5782958e9eca16b3caf4c7742e8d9d24 to your computer and use it in GitHub Desktop.
ESPHOME custom light that provides color temperature support to RGBW lights. This differs from the original (see link in the code) by mapping the RGBW from the
#include "esphome.h"
enum mode {RGB, White};
// Constants
const float maxMired = 500;
const float minMired = 153;
/**
* Map a RGBW Light into a tunable color / RGB Light
*
* Lane Roberts
*
* derived from:
* https://gist.github.com/madjam002/31cc88640efa370630fed6914fa4eb7f
* https://gist.github.com/triphoppingman/76153ddf58072b10e229e9147b2bdf72
*/
class CustomRGBWLight : public Component, public LightOutput {
public:
CustomRGBWLight(
FloatOutput *red,
FloatOutput *green,
FloatOutput *blue,
FloatOutput *white
) {
red_output = red;
green_output = green;
blue_output = blue;
white_output = white;
// Create initial state
colorTemp_ = -1.0f;
brightness_ = -1.0f;
mode_ = White;
// default scaling
cr = 1;
br = 0;
cg = 0.6;
bg = 0;
cb = -1.5;
bb = 0.5;
cw = -0.7;
bw = 1;
}
/**
* Constructor with scaling provided.
*/
CustomRGBWLight(
FloatOutput *red,
FloatOutput *green,
FloatOutput *blue,
FloatOutput *white,
float _br,
float _cr,
float _bg,
float _cg,
float _bb,
float _cb,
float _bw,
float _cw
) {
red_output = red;
green_output = green;
blue_output = blue;
white_output = white;
// Create initial state
colorTemp_ = -1.0f;
brightness_ = -1.0f;
mode_ = White;
// Configured scaling
cr = _cr;
br = _br;
cg = _cg;
bg = _bg;
cb = _cb;
bb = _bb;
cw = _cw;
bw = _bw;
}
/**
* Get the traits for this light
*/
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(minMired); // home assistant minimum 153
traits.set_max_mireds(maxMired); // home assistant maximum 500
return traits;
}
/**
* Write the state to this light
*/
void write_state(LightState *state) override {
float colorTemp, brightness;
state->current_values_as_brightness(&brightness);
colorTemp = state->current_values.get_color_temperature();
float red, green, blue, cwhite, wwhite;
state->current_values_as_rgbww(&red, &green, &blue, &cwhite, &wwhite);
// Switch modes if rgb values have been sent or if color temp value has been sent
if (colorTemp != colorTemp_)
{
mode_ = White;
}
else if (red != oldRed || green != oldGreen || blue != oldBlue)
{
mode_ = RGB;
}
if (brightness != brightness_ && (cwhite > 0.0f || wwhite > 0.0f))
{
mode_ = White;
}
// ESP_LOGD("custom", " CWhite: %.2f | WWhite: %.2f ", cwhite, wwhite);
if(mode_ == White) {
// Normalize the colorTemp
float xaxis = (colorTemp - minMired) / (maxMired - minMired); // Varies from 0 to 1 as it moves from MIN to MAX
// Place the rgb values on three lines
float red = std::min(std::max((cr * xaxis + br) * brightness,0.0f), 1.0f);
float green = std::min(std::max((cg * xaxis + bg) * brightness,0.0f), 1.0f);
float blue = std::min(std::max((cb * xaxis + bb) * brightness,0.0f), 1.0f);
float white = std::min(std::max((cw * xaxis + bw) * brightness,0.0f), 1.0f);
this->red_output->set_level(red);
this->green_output->set_level(green);
this->blue_output->set_level(blue);
this->white_output->set_level(white);
// Store this
colorTemp_ = colorTemp;
} else {
this->red_output->set_level(red);
this->green_output->set_level(green);
this->blue_output->set_level(blue);
this->white_output->set_level(0);
}
this->oldRed = red;
this->oldGreen = green;
this->oldBlue = blue;
brightness_ = brightness;
}
protected:
FloatOutput *red_output;
FloatOutput *green_output;
FloatOutput *blue_output;
FloatOutput *white_output;
float oldRed;
float oldGreen;
float oldBlue;
float colorTemp_;
float brightness_;
mode mode_;
// red intercept and scale
float br;
float cr;
// green intercept and scale
float bg;
float cg;
// blue intercept and scale
float bb;
float cb;
// white intercept and scale
float bw;
float cw;
};
@triphoppingman
Copy link

Nice work! Here is a question - do you know how to set the color of the light at power up?

@vandarin
Copy link
Author

vandarin commented May 8, 2020

I'm assuming you're talking about this scenario:

  1. The light is set to an RGB color
  2. The light is turned off
  3. Home assistant sends a white+temperature state to the bulb
  4. The bulb comes on at RGB white, but the white channel stays at 0.

No, I know why it's doing it, but I haven't reasoned out the logic to fix it yet. Sending XY states and HA profiles don't seem to be doing what I think they should either.

@triphoppingman
Copy link

triphoppingman commented May 8, 2020 via email

@vandarin
Copy link
Author

I think I got it. The logic could be cleaned up a little bit, but sending a state with color_temperature always activates the white channel, and sending brightness does the right thing in both White and RGB modes.

@triphoppingman
Copy link

triphoppingman commented May 11, 2020 via email

@YvesZH
Copy link

YvesZH commented Sep 2, 2020

I have successfully integrated the solution from this guide. Unfortunately the Brightnes slider and Colortemparatur slider is not linear. That's why I tried this solution, unfortunately without success.

I saved the code from above in a file called ColorTempRGBWLight.h. This file is then saved in the following directory: /config/esphome/.
Then I adjusted my "light.yaml" as follows (as it is described here):

esphome:
  name: buro_03_esph
  platform: ESP8266
  board: esp01_1m
  includes:
    - ColorTempRGBWLight.h

wifi:
*******
*******
captive_portal:
logger:
api:
ota:

my9231:
  data_pin: GPIO13
  clock_pin: GPIO15
  num_channels: 4
  num_chips: 1
  bit_depth: 8

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: buro_03_esph
        default_transition_length: 1.5s
        restore_mode: ALWAYS_OFF # because powercut could then cause all lights to turn on
        effects:
          - random:
          - strobe:
          - flicker:


When trying to compile the light.yaml, an error message appears. I think I did something completely wrong. Maybe in the lambda section (i just copy past from here) . Can someone help me (I'm not a programmer)? Thanks a lot

@triphoppingman
Copy link

triphoppingman commented Sep 2, 2020 via email

@YvesZH
Copy link

YvesZH commented Sep 3, 2020

This is shown during i try to compile:


INFO Reading configuration /config/esphome/buro_01_esph.yaml...
INFO Generating C++ source...
INFO Compiling app...
INFO Running:  platformio run -d /config/esphome/buro_01_esph
Processing buro_01_esph (board: esp01_1m; framework: arduino; platform: espressif8266@2.2.3)
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
PACKAGES: 
 - framework-arduinoespressif8266 2.20502.0 (2.5.2) 
 - tool-esptool 1.413.0 (4.13) 
 - tool-esptoolpy 1.20600.0 (2.6.0) 
 - toolchain-xtensa 1.40802.2 (4.8.2)
Dependency Graph
|-- <ESPAsyncTCP-esphome> 1.2.2
|   |-- <ESP8266WiFi> 1.0
|-- <ESP8266WiFi> 1.0
|-- <ESP8266mDNS> 1.2
|   |-- <ESP8266WiFi> 1.0
|-- <ESPAsyncWebServer-esphome> 1.2.6
|   |-- <ESPAsyncTCP-esphome> 1.2.2
|   |   |-- <ESP8266WiFi> 1.0
|   |-- <Hash> 1.0
|   |-- <ESP8266WiFi> 1.0
|-- <DNSServer> 1.1.1
|   |-- <ESP8266WiFi> 1.0
Compiling /data/buro_01_esph/.pioenvs/buro_01_esph/src/main.cpp.o
src/main.cpp: In lambda function:
src/main.cpp:215:28: error: expected type-specifier before 'FrankeverCustomLight'
       auto light_out = new FrankeverCustomLight(output_red, output_green, output_blue, output_white);
                            ^
src/main.cpp:217:24: error: could not convert '{light_out}' from '<brace-enclosed initializer list>' to 'std::vector<esphome::light::LightOutput*>'
       return {light_out};
                        ^
src/main.cpp:218:3: warning: control reaches end of non-void function [-Wreturn-type]
   });
   ^
*** [/data/buro_01_esph/.pioenvs/buro_01_esph/src/main.cpp.o] Error 1
========================= [FAILED] Took 19.90 seconds =========================

@triphoppingman
Copy link

triphoppingman commented Sep 3, 2020 via email

@YvesZH
Copy link

YvesZH commented Sep 3, 2020

Thanks a lot for sharing and answer quickly. In my light.yaml file in the lambda section, i found a mistake (changed from new FrankeverCustomLight to new ColorTempRGBWLight. But the error are similar:

Compiling /data/buro_01_esph/.pioenvs/buro_01_esph/src/main.cpp.o
src/main.cpp: In lambda function:
src/main.cpp:215:28: error: expected type-specifier before 'ColorTempRGBWLight'
       auto light_out = new ColorTempRGBWLight(output_red, output_green, output_blue, output_white);
                            ^
src/main.cpp:217:24: error: could not convert '{light_out}' from '<brace-enclosed initializer list>' to 'std::vector<esphome::light::LightOutput*>'
       return {light_out};
                        ^
src/main.cpp:218:3: warning: control reaches end of non-void function [-Wreturn-type]
   });
   ^
*** [/data/buro_01_esph/.pioenvs/buro_01_esph/src/main.cpp.o] Error 1
========================= [FAILED] Took 20.21 seconds =========================

@triphoppingman
Copy link

triphoppingman commented Sep 4, 2020 via email

@YvesZH
Copy link

YvesZH commented Sep 4, 2020

Current version: 1.14.5 (on hassio)

@triphoppingman
Copy link

triphoppingman commented Sep 4, 2020 via email

@YvesZH
Copy link

YvesZH commented Sep 4, 2020

Thanks for this good support. But still no luck...
Here the file structure:
01

and no error:
2

when I delete the file, an error message appears:
3

And the file it selfs: I copy the text from you in a .txt file and then changed the ending to .h

@triphoppingman
Copy link

triphoppingman commented Sep 4, 2020 via email

@vandarin
Copy link
Author

vandarin commented Sep 4, 2020

I think you have a mismatch between the filename and the class name. The file is named ColorTempRGBWLight.h (use this in the include: block), but if you copied from this gist, the class name that you should use in the lambda is CustomRGBWLight.

auto light_out = new CustomRGBWLight(id(output_red), id(output_green), id(output_blue), id(output_white));

@YvesZH
Copy link

YvesZH commented Sep 5, 2020

Year - now its compile succsessfully
Thanks a lot vandarin

Also thanks to tripphopingman 👍

I think you have a mismatch between the filename and the class name. The file is named ColorTempRGBWLight.h (use this in the include: block), but if you copied from this gist, the class name that you should use in the lambda is CustomRGBWLight.

auto light_out = new CustomRGBWLight(id(output_red), id(output_green), id(output_blue), id(output_white));

@tekgeek1205
Copy link

tekgeek1205 commented May 22, 2022

FYI to anyone that stumbles across this, it doesn't work in the current version of esphome.

`

`
INFO Reading configuration /config/right-desk-lamp.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing right-desk-lamp (board: esp01_1m; framework: arduino; platform: platformio/espressif8266 @ 3.2.0)

HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
Dependency Graph
|-- 1.2.3
|-- 2.1.0
| |-- 1.2.3
| |-- 1.0
| |-- 1.0
|-- 1.1.1
|-- 1.0
|-- 1.2
Compiling .pioenvs/right-desk-lamp/src/main.cpp.o
Archiving .pioenvs/right-desk-lamp/libc74/libESPAsyncWebServer-esphome.a
Archiving .pioenvs/right-desk-lamp/libfb2/libESP8266mDNS.a
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/FSnoop.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/FunctionalInterrupt.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/HardwareSerial.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/IPAddress.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/LwipDhcpServer-NonOS.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/LwipDhcpServer.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/LwipIntf.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/LwipIntfCB.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/MD5Builder.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/Print.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/Schedule.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/StackThunk.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/Stream.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/StreamSend.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/Tone.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/TypeConversion.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/Updater.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/WMath.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/WString.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/abi.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/aes_unwrap.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/base64.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/cbuf.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/cont.S.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/cont_util.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_app_entry_noextra4k.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_eboot_command.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_features.cpp.o
In file included from src/main.cpp:38:
src/ColorTempRGBWLight.h: In member function 'virtual esphome::light::LightTraits CustomRGBWLight::get_traits()':
src/ColorTempRGBWLight.h:92:12: error: 'class esphome::light::LightTraits' has no member named 'set_supports_brightness'; did you mean 'get_supports_brightness'?
92 | traits.set_supports_brightness(true);
| ^~~~~~~~~~~~~~~~~~~~~~~
| get_supports_brightness
src/ColorTempRGBWLight.h:93:12: error: 'class esphome::light::LightTraits' has no member named 'set_supports_rgb'; did you mean 'get_supports_rgb'?
93 | traits.set_supports_rgb(true);
| ^~~~~~~~~~~~~~~~
| get_supports_rgb
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_flash_quirks.cpp.o
src/ColorTempRGBWLight.h:94:12: error: 'class esphome::light::LightTraits' has no member named 'set_supports_rgb_white_value'; did you mean 'get_supports_rgb_white_value'?
94 | traits.set_supports_rgb_white_value(false);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| get_supports_rgb_white_value
src/ColorTempRGBWLight.h:95:12: error: 'class esphome::light::LightTraits' has no member named 'set_supports_color_temperature'; did you mean 'get_supports_color_temperature'?
95 | traits.set_supports_color_temperature(true);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| get_supports_color_temperature
/config/right-desk-lamp.yaml: In lambda function:
/config/right-desk-lamp.yaml:56:28: error: 'ColorTempRGBWLight' does not name a type
56 | auto light_out = new ColorTempRGBWLight.h(id(output_red), id(output_green), id(output_blue), id(output_white));
| ^~~~~~~~~~~~~~~~~~
/config/right-desk-lamp.yaml:58:24: error: could not convert '{light_out}' from '' to 'std::vectoresphome::light::LightOutput*'
58 | return {light_out};
| ^
| |
|
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_flash_utils.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_i2s.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_main.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_non32xfer.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_noniso.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_phy.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_postmortem.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_si2c.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_sigma_delta.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_spi_utils.cpp.o
Compiling .pioenvs/right-desk-lamp/FrameworkArduino/core_esp8266_timer.cpp.o
*** [.pioenvs/right-desk-lamp/src/main.cpp.o] Error 1
========================== [FAILED] Took 2.38 seconds ==========================

@panchomira
Copy link

I would love a workaround :C

@vandarin
Copy link
Author

@panchomira I am no longer using these bulbs, and esphome is no longer compatible with this class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment