I saw someone on TikTok that made a lightning cloud with some addressable LED’s and I had to make my own.
With some spare parts laying around I cobbled something up in just a few hours! the photo doesn’t do it justice
The wiring is very simple, I didn’t get a picture before I stuck it in the foam card, but its a USB-C PD-Buddy V1.0 that I had in a draw for the last few years, set to give a 5v 3A output - which is on the limit for this many LED’s, connected to a D1 mini ESP8266 and then to a string of 96 WS2812B RGB LED’s leftover from an old project. The LED’s were broken up into 4 strips of 24 LED’s. To try and keep the voltage high at the top end of the strip I just jumpered the power up rather than looping it all the way through, on other projects I found this helps keep the colour more even, not that it matters with something like this. Everything is just double sided taped on, including the stuffing from an old pillow
For the lightning effect I couldn’t find exactly what I wanted so I set about creating my own effect. it chooses a random width and a position, and does a really quick, but perceivable flash down, then flashes off then back on with some randomness thrown in, creating quick intense thin bolts through to wide slow bolts. The colour is randomised too, it needs a tweak still… its a bit vibrant at the moment. It was fun trying to figure out the maths to get the positions lined up due to the way the LED’s are looped, got the brain juices flowing good! I also have a few other effects thrown in for fun too, the fireworks effect also looks pretty good for simulating lightning .
esphome:
name: lightning
friendly_name: lightning
esp8266:
board: d1_mini
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "xxx"
ota:
password: "xxx"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Lightning Fallback Hotspot"
password: "xxx"
captive_portal:
web_server:
port: 80
globals:
- id: red_level
type: float
restore_value: no
initial_value: '0'
- id: green_level
type: float
restore_value: no
initial_value: '0'
- id: blue_level
type: float
restore_value: no
initial_value: '0'
- id: width
type: int
restore_value: no
initial_value: '0'
- id: leftness
type: int
restore_value: no
initial_value: '0'
- id: rightness
type: int
restore_value: no
initial_value: '0'
light:
- platform: neopixelbus
type: GRB
variant: WS2811
pin: D4
num_leds: 96
name: "Lightning"
id: lightning_rgb
effects:
- automation:
name: "Lightning Randomised"
sequence:
- light.addressable_set:
id: lightning_rgb
red: 0%
green: 0%
blue: 0%
- delay: 100ms
- lambda: |-
id(red_level) = (((rand() % 100) + 150) / 255.0);
ESP_LOGD("TAG", "Red: %f", id(red_level));
- lambda: |-
id(green_level) = (((rand() % 200) + 50) / 255.0);
ESP_LOGD("TAG", "Green: %f", id(green_level));
- lambda: |-
id(blue_level) = (((rand() % 100) + 150) / 255.0);
ESP_LOGD("TAG", "Blue: %f", id(blue_level));
- lambda: |-
id(width) = (rand() % 23);
ESP_LOGD("TAG", "Width: %d", id(width));
- lambda: |-
id(leftness) = (rand() % (23 - id(width)));
ESP_LOGD("TAG", "Leftness: %d", id(leftness));
- lambda: |-
id(rightness) = (id(leftness) + id(width));
ESP_LOGD("TAG", "Rightness: %d", id(rightness));
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(95 - id(rightness));
range_to: !lambda return(95 - id(leftness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness) + 48);
range_to: !lambda return(id(rightness) + 48);
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(47 - id(leftness));
range_to: !lambda return(47 - id(rightness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness));
range_to: !lambda return(id(rightness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 20ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(95 - id(rightness));
range_to: !lambda return(95 - id(leftness));
red: 0%
green: 0%
blue: 10%
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness) + 48);
range_to: !lambda return(id(rightness) + 48);
red: 0%
green: 0%
blue: 10%
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(47 - id(rightness));
range_to: !lambda return(47 - id(leftness));
red: 0%
green: 0%
blue: 10%
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness));
range_to: !lambda return(id(rightness));
red: 0%
green: 0%
blue: 10%
- delay: 30ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(95 - id(rightness));
range_to: !lambda return(95 - id(leftness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness) + 48);
range_to: !lambda return(id(rightness) + 48);
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(47 - id(rightness));
range_to: !lambda return(47 - id(leftness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: 10ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness));
range_to: !lambda return(id(rightness));
red: !lambda return(id(red_level));
green: !lambda return(id(green_level));
blue: !lambda return(id(blue_level));
- delay: !lambda return((rand() % 100) + 80);
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(95 - id(rightness));
range_to: !lambda return(95 - id(leftness));
red: 10%
green: 0%
blue: 10%
- delay: 20ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness) + 48);
range_to: !lambda return(id(rightness) + 48);
red: 10%
green: 0%
blue: 10%
- delay: 20ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(47 - id(rightness));
range_to: !lambda return(47 - id(leftness));
red: 10%
green: 0%
blue: 10%
- delay: 20ms
- light.addressable_set:
id: lightning_rgb
range_from: !lambda return(id(leftness));
range_to: !lambda return(id(rightness));
red: 10%
green: 0%
blue: 10%
- delay: !lambda return((rand() % 100) + 80);
- light.addressable_set:
id: lightning_rgb
range_from: 0
range_to: 96
red: 0%
green: 0%
blue: 0%
- delay: !lambda return((rand() % 1000 + 1) * 10);
- lambda:
name: randomflicker
update_interval: 200 ms
lambda: |-
auto call = id(lightning_rgb).turn_on();
float r = random_float() * 2.0f - 1.0f;
r = r * r * r;
call.set_transition_length(r);
call.set_brightness(0.7 + r/10);
call.set_publish(false);
call.set_save(false);
call.perform();
- lambda:
name: Chill Mode
update_interval: 60s
lambda: |-
auto call = id(lightning_rgb).turn_on();
call.set_transition_length(5000);
call.set_white(0.0);
esphome::Color c = esphome::Color::random_color();
call.set_rgb((c.red%255)/255.0, (c.green%255)/255.0, (c.blue%255)/255.0);
call.set_publish(false);
call.set_save(false);
call.perform();
- lambda:
name: Chill Mode (Vibrant)
update_interval: 60s
lambda: |-
auto call = id(lightning_rgb).turn_on();
call.set_transition_length(5000);
call.set_white(0.0);
esphome::Color c = esphome::Color::random_color();
call.set_rgb((c.red%128)/255.0, (c.green%128)/255.0, (c.blue%128)/255.0);
call.set_publish(false);
call.set_save(false);
call.perform();
- lambda:
name: Disco
update_interval: 500ms
lambda: |-
auto call = id(lightning_rgb).turn_on();
call.set_transition_length(rand() % 400 + 1);
//call.set_transition_length(500);
call.set_white(0.0);
esphome::Color c = esphome::Color::random_color();
call.set_rgb((c.red)/255.0, (c.green)/255.0, (c.blue)/255.0);
call.set_publish(false);
call.set_save(false);
call.perform();
- lambda:
name: WTF
update_interval: 200ms
lambda: |-
auto call = id(lightning_rgb).turn_on();
call.set_transition_length(200);
call.set_white(0.0);
call.set_brightness((rand() % 255 + 1) / 400.0);
call.perform();
- addressable_rainbow:
name: Rainbow
speed: 10
width: 15
- addressable_scan:
name: Scan
move_interval: 50ms
scan_width: 1
- addressable_twinkle:
name: Twinkle
twinkle_probability: 5%
progress_interval: 32ms
- addressable_random_twinkle:
name: Colour Twinkle
twinkle_probability: 5%
progress_interval: 32ms
- addressable_fireworks:
name: Fireworks
update_interval: 32ms
spark_probability: 10%
use_random_color: false
fade_out_rate: 80
- addressable_fireworks:
name: Fireworks Slow
update_interval: 64ms
spark_probability: 20%
use_random_color: false
fade_out_rate: 90
- addressable_fireworks:
name: Colour Fireworks
update_interval: 32ms
spark_probability: 8%
use_random_color: true
fade_out_rate: 80
my plan is to change between the fireworks effect and the random lightning effects and see how it looks… ill update once i get it looking nice.
I’ve also ordered a speaker, I want to mess around with making some thundery sounds to go with it, maybe some rain sounds too