When I saw LEGO announcing the new Nightmare Before Christmas sets, I knew it was going to be mine! On its own it’s already a great set! It has the right mix of minifigures (with a long legged Jack!!) and captures all the iconic locations, especially with Jack & Sally being placed in front of a huge Moon element!
But…me being me, I wanted to see if I could make the entire set a bit spookier, or at least even more visually interesting, especially at night!
I started messing around with LEGO and various lighting solutions a couple of years ago, as a way to level up our LEGO Christmas Village, and so far I wasn’t 100% happy with the result. I think what I achieved with the Nightmare Before Christmas set is going to be THE way of doing it event at a larger scale later this year!
So, what is it that I’ve done then? The core is similar to my recent experiments with ESP32 and ESPHome. Reason being that I wanted to have a simple way to interact with the final result as part of my HomeAssistant installation. I have various routines turning on lights at sunset and off when going to sleep, so it made sense to try and include this LEGO mod in those routines!
The set is super detailed, and it’s broken down in three big chunks, which also made it easier to route the many cables I had to deal with (more on that later). I wanted to make sure the lights were not going to distract, but only enhance the result, and that they could be seen as plausible additions to the overall set.
I was initially driven by the inclusion of two carved pumpkin heads in the set. It seemed logical to give them the effect of having a flickering candle inside!
Next, I wanted to light up from the inside of the main house building. There are two small windows, and again it made sense to include something there.
Finally, I wanted to sprinkle some additional lights here and there, to raise the spooky level a tad more. I went into my stockpile of extra bits of LEGO and found a couple of lantern holders that seemed appropriate to include.
I thought I was done, but then looking at the set, it seemed obvious I should have done something for the big moon piece, so I included that as well in the list of lights.
Then something else came up: the set doesn’t include a lamppost, but it’s an element often seen in the movie, plus I was thinking it was going to be a nice way to bring more light to the foreground and to some of the included characters.
Let’s talk hardware! Now that all the light points have been identified, how do we bring them to life? As I mentioned at the top, the brain of the operation it’s going to be an ESP32 board. For each light point I then found some tiny coloured diodes. The size of the light was massively important in order to easily fit in/around LEGOs. The ones I found on Amazon are tiny, inexpensive and fairly bright, so bingo!
Next step was to figure out the pin layout and connections between the board and the lights. Enter ChatGPT o1 model! The use of ChatGPT o1 has been instrumental for this project. I was able to describe what I wanted to achieve and the model gave step by step instructions on how to make it real. The new model is also much more “verbose” in the results given, so you can really understand what each step means and its meant to do, making it easier for me to tweak the final code and effects to my preference.
There aren’t many lights and they are fairly easy to drive power-wise, so the resulting layout was something like this:
Which in reality looks something like this!
You may notice from the wiring diagram that the lights are grouped in 3 blocks. I didn’t need individual control on each light, so I grouped them based on the effect I wanted to achieve: the pumpkins and lanterns have an-always on flicker, the lamppost and the window lights are mostly static, with a random flicker introduced from time to time and then I wanted to have a static light for the moon.
These 3 blocks are then translated to 3 individual triggers inside HomeAssistant, so various automations can manage each individually.
Now let’s talk about the importance of 3D printing for this project. From the last picture, you can see some (if you zoom in) some transparent element and the black lamppost. I didn’t have a “real” LEGO lamp post, so guess what: I 3D printed one and it fit perfectly! Also, I didn’t have enough 1×1 transparent round bricks, so I 3D printed those too. I used transparent PETG and it worked perfectly. I also made a small modification to the standard brick, so I could feed the small LED on the side, without impacting on the clutch power of the base of the brick. A small detail, but it made a world of difference when assembling the final bits together.
A quick test and fine-tune of the code, and it was all working! It took about a couple of hours to fine-tune the code with the effects being exactly what I wanted, but the latest ChatGPT o1 model made it fairly easy to constantly iterating on the code base, in order to get to the desired result. You can see the code itself it’s fairly easy and straightforward!
substitutions:
name: esphome-web-41f9dc
friendly_name: Lego Village Lights
esphome:
name: ${name}
friendly_name: ${friendly_name}
min_version: 2024.6.0
name_add_mac_suffix: false
project:
name: esphome.web
version: dev
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
# Allow Over-The-Air updates
ota:
- platform: esphome
# Allow provisioning Wi-Fi via serial
improv_serial:
wifi:
# Set up a wifi access point
ap: {}
# In combination with the `ap` this allows the user
# to provision wifi credentials to the device via WiFi AP.
captive_portal:
dashboard_import:
package_import_url: github://esphome/example-configs/esphome-web/esp32.yaml@main
import_full_config: true
# Sets up Bluetooth LE (Only on ESP32) to allow the user
# to provision wifi credentials to the device.
esp32_improv:
authorizer: none
# To have a "next url" for improv serial
web_server:
output:
- platform: ledc
pin: GPIO16 # Candle Light
frequency: 1000 Hz
id: pwm_output_candle
- platform: ledc
pin: GPIO17 # Buzzing Light Bulb
frequency: 1000 Hz
id: pwm_output_bulb
- platform: ledc
pin: GPIO18 # Third Light (Always On, Dimmable)
frequency: 1000 Hz
id: pwm_output_third_light
light:
# Candle Light
- platform: monochromatic
name: "Candle Light"
output: pwm_output_candle
effects:
- flicker:
name: Candle Flicker
alpha: 95% # Smoother transitions for a softer flicker
intensity: 10% # Lower intensity for gentle flickering
# Buzzing Light Bulb with custom behavior
- platform: monochromatic
name: "Buzzing Light Bulb"
output: pwm_output_bulb
id: buzzing_light
effects:
- flicker:
name: Buzzing Flicker
alpha: 50% # Faster transitions to simulate buzzing
intensity: 30% # Higher intensity for sharper fluctuations
# Third Light (Always On, Dimmable)
- platform: monochromatic
name: "Moon"
output: pwm_output_third_light
id: third_light
gamma_correct: 1.0 # Optional: Adjusts dimming curve for linear brightness
Now it was time to assemble! The final step was again a piece of 3D printing magic. I traced the base of the set and printed a black base that could house and hide all the rat-nest of cabling and the ESP32!
The base was broken in two pieces as it was way too big to be printed in one go! The slot at the back is used to feed all the cables down below so they don’t show from the front when looking at the set.
Now I guess the final question is: was the time and effort worth it?
1000000% yes!
Just look at the final result!!
(And yes, the small plants behind it helps a lot with the spookiness!!)