I rigged up some holiday lights that switch between a number of color palettes based on what holiday is coming up next. I used a $25 light strip, a $5 WiFi microcontroller (ESP8266), and Home Assistant to make it all happen.
Setting up the light strip
Using a “NeoPixel”-like addressable RGB light strip is pretty well-covered online these days. I got this waterproof one. I plugged in one of my ESP8266’s and loaded it up with some demo code from the FastLED library. I bought an outdoor waterproof enclosure for the 5V power supply and ran outdoor wires in a small trench over to my fence, where I then used one of these outdoor wire coupler things to both protect the connection and store the ESP8266 itself.
I wrote code to have it connect to my local mosquitto MQTT server (running on my home server, but you can also run on e.g. a raspberry pi) using the PubSub arduino MQTT client library. It subscribes to two topics, one for controlling the mode (off, twinkle, alarm, solid), and the other for controlling the color palette.
Given a MQTT-controlled WiFi lightstrip, adding the holiday smarts to Home Assistant is the next step.
Figuring out what holiday is next
I surveyed the existing options for figuring out what the next holiday is but came up short, so I made a new custom component for home assistant that builds a Next Holiday sensor. The sensor tells you what holiday is coming up next, how many days out it is, and whether or not today is that holiday. It also exposes a list of all holidays of the year.
Arguably, this capability might make sense to integrate into the built-in workday sensor, which uses the same underlying library.
The underlying library only considers national and state/provincial holidays in scope, so to get popular holidays like Easter and Hanukkah, I had to figure out which countries considered them official. The alternate would be to allow custom holiday labels in the config, but I wanted to leverage the complex logic for e.g. figuring out when Easter is.
So here’s the configuration that gets some pretty common holidays for people in the USA:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
- platform: next_holiday sources: - country: "USA" state: "WA" - country: "Australia" # Easter is a national holiday in NSW province: "NSW" filter: - 'easter sunday' - country: "Jamaica" filter: - 'valentine' - country: "Ireland" filter: - 'patrick' - country: "Israel" # Hanukkah is a national holiday in Israel multiday: true filter: - 'hanukkah' |
Setting the colors
For now, I just coded the color options directly into the ESP8266. I might upgrade later to allow Home Assistant to send the color palette over MQTT for better flexibility. Here are the colors I set (FastLED lets you use HTML color names).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
CRGB cThanksgiving[] = { CRGB::Yellow, CRGB::Orange, CRGB::Red, CRGB::Green, }; CRGB cHanukka[] = { CRGB::White, CRGB::Blue, }; CRGB cChristmas[] = { CRGB::Red, CRGB::Green, }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
CRGB cUsa[] = { CRGB::White, CRGB::Blue, CRGB::Red, }; CRGB cPatrick[] = { CRGB::Green, }; CRGB cEaster[] = { CRGB::Pink, CRGB::CornflowerBlue, CRGB::LightSeaGreen, }; |
1 2 3 4 5 6 7 8 9 10 |
CRGB cValentine[] = { CRGB::Pink, CRGB::Red, }; CRGB cNewyear[] = { CRGB::Gold, CRGB::White, }; |
Then I just set up a Home Assistant input select to have all the holidays of interest:
Automatically updating colors when holiday changes
With colors, control, and holidays all loaded up, I just needed a few automations to tie them all together. This one watches the Next Holiday sensor, and when it changes, it updates the color-choosing Input Selector to match the upcoming holiday.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
automation: - alias: Update holiday colors # look at next holiday and set input select manually trigger: - platform: state entity_id: sensor.next_holiday - platform: time at: '06:30:00' action: - service: input_select.select_option target: entity_id: input_select.lightstrip_colors data: option: | {## Map holidays to color options ##} {% set hol = states.sensor.next_holiday.state | lower %} {% if 'hanukkah' in hol -%} Hanukkah {%- elif 'thanksgiving' in hol -%} Thanksgiving {%- elif 'christmas' in hol -%} Christmas {%- elif 'memorial' in hol -%} USA {%- elif 'luther' in hol -%} Christmas {%- elif 'independence' in hol -%} USA {%- elif 'veterans' in hol -%} USA {%- elif 'washington' in hol -%} USA {%- elif 'patrick' in hol -%} St. Patrick {%- elif 'easter' in hol -%} Easter {%- elif 'valentine' in hol -%} Valentine {%- elif 'new year' in hol -%} New Year {%- endif %} |
Then there’s one more automation that watches the Input Select for changes and sends MQTT commands to the light strip when it changes. This works both when you’re selecting the colors manually in the UI and when the automatic holiday-watching automation above changes it.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
automation: - alias: Lightstrip colors trigger: platform: state entity_id: input_select.lightstrip_colors action: - service: mqtt.publish data: topic: home/lightstrip/colors payload_template: | {% set option_number = state_attr(trigger.entity_id,'options').index(states(trigger.entity_id)) %} {{option_number}} retain: true |
The template code above just maps from input select name to input select numerical index for convenience, based on this.
On the ESP8266, the corresponding code in the callback function maps the indices to the actual color palettes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
void callback(char* topic, byte* payload, unsigned int length) { char command = (char)payload[0]; if (strstr(topic, "mode")) { // operation mode if (command == '0') { turn_off(); } else if (command == '1') { run_default_mode(); } else if (command == '2') { alarm(); } else if (command == '3') { light_it_up(); } } else { // color mode if (command == '0') { activate_cHanukka_colors(); } else if (command == '1') { activate_thanksgiving_colors(); } else if (command == '2') { activate_christmas_colors(); } else if (command == '3') { activate_usa_colors(); } else if (command == '4') { activate_patrick_colors(); } else if (command == '5') { activate_easter_colors(); } else if (command == '6') { activate_valentine_colors(); } else if (command == '7') { activate_newyear_colors(); } } } |
As seen in the video, there’s also a ‘security alert’ mode that flashes the light and a light-up mode that just illuminates the area. Those will be integrated with a motion sensor soon to trigger them appropriately.
Anyway, pretty fun stuff. I’m looking forward to watching the colors change as the years go on.