I am new to ESPhome and am hoping someone can provide some help.
I have a working custom ESP32 based device on the RGB platform that I want to add an optional mode to flash the RGB light for special indication. Under normal circumstances, I would control the RGB light normally via either dashboard control and/or automations - when a special indication was desired, a “Flash RGB LED” switch would be turned ON and a special RGB color would be set in the ESP32 RGB device, which would then flash (~0.25Hz) this color in a sinusoidal fashion for as long as this “Flash RGB LED” switch was set. Once the “Flash RGB LED” was turned OFF, the device would return to the traditional RBG light platform.
I found an example that appears to flash an RGB light in ESPhome, though is instead based on the WS2812B chipset versus the RGB platform - the example is located here:
I have tried to integrate this lambda code into my existing RGB code as follows:
esphome:
name: motion-rgb-illuminance-62-84
friendly_name: motion-rgb-illuminance-62-84
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: ${friendly_name}_AP
password: "password"
captive_portal:
web_server:
include_internal: true # This will show internal entities like sensors
switch:
# Switch for flashing RBG LED
- platform: gpio
name: Flash RGB LED
id: flash_rgb_led
pin: GPIO32
restore_mode: RESTORE_DEFAULT_OFF
icon: mdi:pipe-valve
# Note Kingbright WP154A4SEJ3VBDZGW RBG LED has RBG vs RGB
output:
- platform: ledc
pin: GPIO2
frequency: 25000 Hz
id: led_red
- platform: ledc
pin: GPIO4
frequency: 25000 Hz
id: led_green
- platform: ledc
pin: GPIO0
frequency: 25000 Hz
id: led_blue
light:
- platform: rgb
name: "RGB LED"
id: rgb_led
red: led_red
green: led_green
blue: led_blue
effects:
- lambda:
name: Flash LED
update_interval: .05s
lambda: |-
if (id(flash_rgb_led).state) {
static float in = 0.0;
static float out = 0.0;
// Scale sin output from -1/1 to 0/1
out = sin(in) * 0.5 + 0.5;
auto call = id(rgb_led).turn_on();
call.set_rgb(1.0, 0.0, 0.0);
call.set_brightness(out);
// Do not publish state to eliminate flooding of logs
call.set_publish(false);
call.set_save(false);
call.perform();
// RESOLUTION
in += 0.0754;
if (in > 6.283)
in = 0;
}
binary_sensor:
- platform: gpio
pin: GPIO13
name: "PIR Sensor"
device_class: motion
# See https://iambuschi.substack.com/p/diy-esphome-light-sensor
sensor:
- platform: resistance
sensor: source_sensor
configuration: DOWNSTREAM
resistor: 1kOhm
name: "Light Sensor"
unit_of_measurement: "lx"
device_class: "illuminance"
state_class: "measurement"
accuracy_decimals: 1
filters:
- calibrate_linear:
method: exact
datapoints:
- 170.0 -> 1076.4
- 2000.0 -> 21.52
- 21000.0 -> 0.0
- platform: adc
id: source_sensor
pin: GPIO39
attenuation: 11db
# Display IP, MAC, and other Wi-FI stats
text_sensor:
- platform: wifi_info
ip_address:
name: ESP IP Address
mac_address:
name: ESP Mac Wifi Address
ssid:
name: ESP Connected SSID
scan_results:
name: ESP Latest Scan Results
dns_address:
name: ESP DNS Address
I initially commented out the “call.set_rgb(1.0, 0.0, 0.0);” command, however the brightness never changed. I removed this comment to test to see if I could even get RED to flash - only then could I occasionally get the RED to very, very slowly appear under certain circumstances (“Flash RGB LED” switch ON, “Flash LED” ON, ?) however it took several seconds to reach maximum RED brightness, and did not appear to cycle back to dim.
I suspect I am improperly blending WS2812B constructs with the RGB platform in addition to probably several other taboos based on my lack of understanding… This leads to many further questions:
Why is the flash frequency so slow?
Why does the flash only ramp up and not cycle between bright and dim?
Does “set_rbg” also have to be set within the “lamda” loop or can it just use the “global” RGB settings?
I used the term “sinusoidal” to represent a gradual, smooth brightness cycling fade from light and dark versus cycling between On and Off - I prefer Sine wave brightness shifts versus Square wave or Triangular wave brightness changes. Thanks.
I am not seeing how setting transition length and update_interval (+15%) will generate a sine wave output. Can you post code that you think addresses my solution? Thank you.
It doesn’t, but visually similar to it.
You can’t use light component to produce sine wave without considering gamma correction…
But I don’t see the point here, your eye don’t see pure sine wave light output as you would expect.
Worrying about gamma correction is overkill for this application - just trying to get a relatively sinusoidal brightness effect. I have used sine brightness effect multiple times in other projects (written in assembly language, ADA, C++, etc.) with great success - unfortunately, I am not fluent in ‘newer’ languages. Still hoping someone can offer a solution. Thanks.
Removed the “Flash RGB LED” switch and instead using Effect option only to enable Flash - updated Effects section as follows:
effects:
- lambda:
name: Flash LED
update_interval: .05s
lambda: |-
static float in = 0.0;
static float out = 0.0;
auto call = id(rgb_led).turn_on();
// Transition of 50ms = 0.05s
call.set_transition_length(50);
// Scale sin output from -1/1 to 0/1
out = sin(in) * 0.5 + 0.5;
// call.set_rgb(1.0, 0.0, 0.0);
call.set_brightness(out);
// Do not publish state to eliminate flooding of logs
call.set_publish(false);
call.set_save(false);
call.perform();
// RESOLUTION
in += 0.0754;
if (in > 6.283)
in = 0.0;
Can now also use this sensor to indicate when packages are delivered by flashing the corresponding carrier service color when they deliver a package:
US Mail Delivered – RGB (218, 41, 28)
Amazon Delivered – RGB (19, 153, 255)
UPS Delivered – RGB (250, 184, 10)
FedEx Delivered – RGB (102, 0, 153)
The Flash Effect is cleared and the RGB LED is returned to previous mode when the door to retrieve package(s) is opened…
Its always best if you just take a moment and test things in real life. This way there’s no misunderstand about what does what and also, if you have any preconceived thoughts about things then testing is a great way to correct for those too!
This is just me personally but, I find that if i setup circuits and test things then I have a far higher probability that ill remember those little things and it makes huge differences and often speeds up your future prototyping because you’ve used those things already and learned the basics so that i dont have to learn them now.
There are so many configuration options and then if you get into custom lambda effects then you might as well go ahead and plan on doing 10’s or dozens of refreshing that board to see how code changes actually look like in reality so, i wouldn’t even waste time refusing to try things because you assume it would or wouldn’t work a specific way… Just try things and then if its wrong then move on with confidence instead of regret.
Trust me on stuff like this too, I was a student under Mr. Miyagi and Daniel Son or you may know him as the Karate Kid but, in all honesty he punches like a girl so, Patience Grasshopper!!
Added four additional pseudo “flash” RGB lights (on unused pins) to allow storing up to four colors with individual brightness to be cycled through during the flash cycle. The “flash” colors and brightness will be included in the flash cycle by turning the corresponding pseudo “flash” RGB light ON while the “Flash LED” Effect is enabled on the primary “RGB LED”. Updated code:
esphome:
name: motion-rgb-lumen-indicate-62-84
friendly_name: motion-rgb-lumen-indicate-62-84
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: ${friendly_name}_AP
password: "password"
captive_portal:
web_server:
include_internal: true # This will show internal entities like sensors
# Note Kingbright WP154A4SEJ3VBDZGW RBG LED has RBG vs RGB
output:
- platform: ledc
pin: GPIO2
id: led_red
- platform: ledc
pin: GPIO4
id: led_green
- platform: ledc
pin: GPIO0
id: led_blue
# Use four psuedo RGB lights to store alternate flash colors
- platform: ledc
id: red1
pin: GPIO12
- platform: ledc
id: green1
pin: GPIO14
- platform: ledc
id: blue1
pin: GPIO16
- platform: ledc
id: red2
pin: GPIO17
- platform: ledc
id: green2
pin: GPIO18
- platform: ledc
id: blue2
pin: GPIO19
- platform: ledc
id: red3
pin: GPIO21
- platform: ledc
id: green3
pin: GPIO22
- platform: ledc
id: blue3
pin: GPIO23
- platform: ledc
id: red4
pin: GPIO25
- platform: ledc
id: green4
pin: GPIO26
- platform: ledc
id: blue4
pin: GPIO27
light:
# Use four psuedo RGB lights to store alternate flash colors
- platform: rgb
name: "Flash1"
id: flash1
red: red1
green: green1
blue: blue1
- platform: rgb
name: "Flash2"
id: flash2
red: red2
green: green2
blue: blue2
- platform: rgb
name: "Flash3"
id: flash3
red: red3
green: green3
blue: blue3
- platform: rgb
name: "Flash4"
id: flash4
red: red4
green: green4
blue: blue4
# Primary RGB light
- platform: rgb
name: "RGB LED"
id: rgb_led
red: led_red
green: led_green
blue: led_blue
effects:
- lambda:
static bool flash1_on = 0;
static bool flash2_on = 0;
static bool flash3_on = 0;
static bool flash4_on = 0;
static int num_alternates = 0;
static int step = 0;
static float in = 0.0;
static float out = 0.0;
static float r = id(rgb_led).remote_values.get_red();
static float g = id(rgb_led).remote_values.get_green();
static float b = id(rgb_led).remote_values.get_blue();
static float l = id(rgb_led).remote_values.get_brightness();
auto call = id(rgb_led).turn_on();
// Transition of 50ms = 0.05s
call.set_transition_length(50);
// Scale and shift sin output from -1/1 to 0/1
out = sin(in + 4.71239) * 0.5 + 0.5;
call.set_brightness(out * l);
in = in + 0.083776;
if (in > 6.2832)
{
in = 0.0;
flash1_on = (id(flash1).remote_values.is_on() > 0);
flash2_on = (id(flash2).remote_values.is_on() > 0);
flash3_on = (id(flash3).remote_values.is_on() > 0);
flash4_on = (id(flash4).remote_values.is_on() > 0);
num_alternates = 0;
if (flash1_on) num_alternates = num_alternates + 1;
if (flash2_on) num_alternates = num_alternates + 1;
if (flash3_on) num_alternates = num_alternates + 1;
if (flash4_on) num_alternates = num_alternates + 1;
if ( (step == 0) && (num_alternates > 0) )
{
step = 1;
}
if ( (step > 0) && (num_alternates == 0) )
{
step = 0;
}
if (step == 1)
{
if (flash1_on)
{
r = id(flash1).remote_values.get_red();
g = id(flash1).remote_values.get_green();
b = id(flash1).remote_values.get_blue();
l = id(flash1).remote_values.get_brightness();
}
else if (flash2_on)
{
r = id(flash2).remote_values.get_red();
g = id(flash2).remote_values.get_green();
b = id(flash2).remote_values.get_blue();
l = id(flash2).remote_values.get_brightness();
}
else if (flash3_on)
{
r = id(flash3).remote_values.get_red();
g = id(flash3).remote_values.get_green();
b = id(flash3).remote_values.get_blue();
l = id(flash3).remote_values.get_brightness();
}
else if (flash4_on)
{
r = id(flash4).remote_values.get_red();
g = id(flash4).remote_values.get_green();
b = id(flash4).remote_values.get_blue();
l = id(flash4).remote_values.get_brightness();
}
}
else if (step == 2)
{
if ( flash2_on && flash1_on )
{
r = id(flash2).remote_values.get_red();
g = id(flash2).remote_values.get_green();
b = id(flash2).remote_values.get_blue();
l = id(flash2).remote_values.get_brightness();
}
else if ( flash3_on && (flash2_on || flash1_on) )
{
r = id(flash3).remote_values.get_red();
g = id(flash3).remote_values.get_green();
b = id(flash3).remote_values.get_blue();
l = id(flash3).remote_values.get_brightness();
}
else if (flash4_on)
{
r = id(flash4).remote_values.get_red();
g = id(flash4).remote_values.get_green();
b = id(flash4).remote_values.get_blue();
l = id(flash4).remote_values.get_brightness();
}
}
else if (step == 3)
{
if (flash3_on && flash2_on && flash1_on)
{
r = id(flash3).remote_values.get_red();
g = id(flash3).remote_values.get_green();
b = id(flash3).remote_values.get_blue();
l = id(flash3).remote_values.get_brightness();
}
else if (flash4_on)
{
r = id(flash4).remote_values.get_red();
g = id(flash4).remote_values.get_green();
b = id(flash4).remote_values.get_blue();
l = id(flash4).remote_values.get_brightness();
}
}
else if (step == 4)
{
r = id(flash4).remote_values.get_red();
g = id(flash4).remote_values.get_green();
b = id(flash4).remote_values.get_blue();
l = id(flash4).remote_values.get_brightness();
}
else
{
r = id(rgb_led).remote_values.get_red();
g = id(rgb_led).remote_values.get_green();
b = id(rgb_led).remote_values.get_blue();
l = id(rgb_led).remote_values.get_brightness();
}
step = step + 1;
if ( step > num_alternates)
{
step = 1;
}
}
call.set_rgb(r, g, b);
// Do not publish state to eliminate flooding of logs
call.set_publish(false);
call.set_save(false);
call.perform();
binary_sensor:
- platform: gpio
pin: GPIO13
name: "PIR Sensor"
device_class: motion
# See https://iambuschi.substack.com/p/diy-esphome-light-sensor
sensor:
- platform: resistance
sensor: source_sensor
configuration: DOWNSTREAM
resistor: 1.0kOhm
name: "Light Sensor"
unit_of_measurement: "lx"
device_class: "illuminance"
state_class: "measurement"
accuracy_decimals: 1
filters:
- calibrate_linear:
method: exact
datapoints:
- 170.0 -> 1076.4
- 2000.0 -> 21.52
- 21000.0 -> 0.0
- platform: adc
id: source_sensor
pin: GPIO39
attenuation: 12db
update_interval: 60s