For this project, I wanted to build a miniature replica of the Christmas lights wall from Stranger Things. If you haven't seen the first season of Stranger Things yet, do yourself a favor and add it to your watch queue ASAP! It's pretty great.
Check out this video clip for a reference to the wall. Winona Ryder's character essentially uses black paint and a strand of Christmas lights to create an alphabet Ouija board on her living room wall—in order to communicate with her son who is trapped in another dimension. Her son is able to spell out messages by illuminating the corresponding light bulbs, letter-by-letter.
Many other makers have already built versions of this Stranger Things wall with some neat and creative features (e.g. SparkFun's live Twitter wall), but none of them really looked very accurate to the show... I wanted my replica to mimic the creepy aesthetic and be used as a "wall" art piece, so I incorporated a laser to engrave the exact paint strokes.
The finished product was given as a gift to my friend, Regina. It featured addressable LEDs, a battery-powered Bluetooth microcontroller, and a companion mobile application that could be used to display messages remotely.
- C3 Christmas Lights
- Small Addressable RGB LEDs (I used WS2812B-2020)
- LED Breakout Boards
- Solid Core Wire, 22 AWG
- Heat Shrink Tubing
- 12" x 24" Birch Plywood
- 12" x 24" Frame
- Sheets of 12" x 12" Decorative Paper (I couldn't find the exact wallpaper design)
- Battery-powered BLE Microcontroller Board (I used a custom-built one from an old project)
- Male and Female 0.1" Header Pins
- Anodized Aluminum Sheet
- Epilog Mini 24 60W Laser (courtesy of Harris County Public Library)
- Soldering iron with hot air rework station; electric skillet
- Solder wire and solder paste
- Fine point tweezers
- Wire stripper/cutter
- Hot glue gun
- Glue stick
- Super glue
- Black paint and brush
- Black ink pen
- Measuring tape
This project mainly consists of three separate parts: laser engraving the alphabet, constructing a custom Christmas lights strand, and writing the control software. The most tedious part was definitely the lights strand because it was all done manually by hand... and there are 26 letters in the English alphabet. But I'm pretty proud with how it all turned out.
In order to do the laser engraving, we need to provide a black/white image to the Epilog laser software. Since I only want to engrave the alphabet paint strokes, they must be segmented from the rest of the wall (remove the Christmas lights, wallpaper, etc.) in the source image. I used Gimp and Adobe Illustrator image editing tools to adjust the threshold levels and erase any unwanted artifacts. Then I resized the binary image to fit my 12" x 24" canvas.
*Note: the 'Z' character was originally omitted in my source image, which is why it doesn't quite match up...
Next, prepare the canvas by glueing wallpaper to the plywood. I used a glue stick and wallpaper samples that had a similar floral design as the one from the show.
Make sure to test your laser engraving settings on a piece of scrap plywood first! You'll want to dial in the speed/power settings to etch through the paper and a layer of plywood, but not burn it! I did not do this and got burn marks on my expensive wallpaper... so I had to start over using two sheets of 12"x12" decorative paper. Also, make sure the canvas is properly aligned on the bed. Then, just let the laser do the work!
Unfortunately, I did not have the foresight to record a video of the laser engraving. But here is an image of the laser I used and the finished engraving job. I think it took about 45 minutes to finish.
Fill in the engraved letters with black paint. Be careful not to drip any extra paint marks. I also found it helpful to use a black ink pen to touch up the narrow regions in the wood.
In order to illuminate one light bulb at a time, the light strand needs to use addressable LEDs. I found small C3-sized Christmas lights on Amazon, but they were not addressable... so I decided to retrofit the bulbs with small NeoPixel RGB LEDs. These LEDs are addressable and very popular among electronics hobbyists. Each LED would need to be daisy-chained with three wires to provide 3V, ground, and a data signal. Knowing this, I designed small breakout printed circuit boards that could support the C3 bulb and connect each LED to the daisy-chain with wires. The breakout board PCB was designed in Altium and fabricated by OSH Park for ~$0.10/board.
These LEDs and breakout boards are quite small at ~7x7 mm. Instead of soldering the heat-sensitive parts by hand, I decided to use solder paste and an electric skillet (the poor man's reflow oven). I found it helpful to use a microscope and stencil to apply the paste to the pads, then use tweezers to carefully place the LED. I didn't bother with soldering the decoupling capacitor in order to allow more space for mounting the light bulb.
Repeat this process at least 26 times...
After all the boards are populated, place them on the electric skillet. Cover and turn up the heat. Try to follow the reflow profile for the LEDs, but ultimately keep an eye on the solder paste and watch when it gets hot enough to make a solid joint. I like using low-temp solder paste for this.
The next step is to add wires to connect each LED breakout board together. These addressable LEDs work in a daisy-chain configuration with 3 input signals (VDD, GND, DIN) and 3 output signals (VDD, GND, DOUT). To keep track of the signals, I color-coded the wires using a standard convention of VDD=red, GND=black, DATA=white. I selected solid core 22 AWG gauge wire because it is easy to solder to through-hole pads and the wire itself holds its shape when bent.
Careful planning must be done to measure the wires between each LED. You must account for the space between the letters, but also leave room for wire stripping and soldering. It was helpful to use a measuring tape and a wire stripper/cutter for this task. To make it easier to mount the Christmas lights to the plywood, I decided to split the lights into three separate strands, one for each row of letters. This makes it look cleaner from the front, while the daisy-chain connection is managed in the back behind the frame. For this, I used 0.1" male and female header pins to effectively make extension cables.
I also added heat shrink tubing between each LED to make it look like a single black cable, matching how Christmas lights normally look. Cut to size and make sure to add these measured strips of heat shrink before soldering the next breakout board in the chain. After soldering the neighboring wires, use hot air or a lighter flame to activate the heat shrink tubing.
As you are adding new LEDs to the daisy-chain, it is good practice to test that the LEDs are functional and in the correct position. An easy way to check this is by connecting the strand to an Arduino and using Adafruit's NeoPixel library strandtest example to illuminate the LEDs. Once all of the LEDs have been verified to work, you are ready to mount the Christmas light bulbs to the breakout boards.
The C3 Christmas lights that I bought didn't have easily removable plastic bulbs. I needed to pry them off and use a cutter to carefully expose a large enough hole at the bulb base for the LED to shine through. Without cutting the plastic base, the LED would not properly diffuse light inside of the bulb; it needed to be flush to maximize light throw. Once 26 bulbs were removed, I arranged them in a color order to avoid any same-color neighbors. Using a hot glue gun, add a dab of hot glue on top of the LED and quickly apply the plastic bulb to the breakout board. Hold together for a few seconds for the surfaces to bond. The hot glue acts as an adhesive, but also works to diffuse light inside the bulb. Repeat this glueing process for all remaining LEDs, also using super glue if a stronger bond is needed. Pay attention to the orientation of each bulb, as some need to point at different angles.
After mounting the bulbs, test the light strand again to see how the bulbs look when illuminated.
The control software consists of microcontroller firmware to drive the LEDs and respond to Bluetooth commands from a companion mobile application. I used custom-built electronics from a previous project because it already contained the necessary components to power several LEDs with a Lithium-polymer battery. This custom board used a Nordic nRF52832 BLE System-on-Chip, which could easily connect to any Android or Apple smartphone device. The software is fairly straightforward... so any dev board like Arduino, Raspberry Pi, ESP32, or XIAO should also work fine. Just make sure it can adequately drive and control 26 LEDs.
Once you are able to turn on/off a specific LED in the daisy-chain, you just need to translate the text characters into light commands. To do this, I leveraged the ASCII standard, which already represents each character with a unique number (shown below in decimal and hex). Note that a space character is represented by 0x20, and upper- and lowercase A-z letters use different values. The leftmost column represents the LED index value in the Christmas lights daisy-chain.
# | Character | ASCII Dec | ASCII Hex | ASCII Dec | ASCII Hex |
---|---|---|---|---|---|
- | Space | 32 | 0x20 | -- | -- |
0 | A, a | 65 | 0x41 | 97 | 0x61 |
1 | B, b | 66 | 0x42 | 98 | 0x62 |
2 | C, c | 67 | 0x43 | 99 | 0x63 |
3 | D, d | 68 | 0x44 | 100 | 0x64 |
4 | E, e | 69 | 0x45 | 101 | 0x65 |
5 | F, f | 70 | 0x46 | 102 | 0x66 |
6 | G, g | 71 | 0x47 | 103 | 0x67 |
7 | H, h | 72 | 0x48 | 104 | 0x68 |
8 | I, i | 73 | 0x49 | 105 | 0x69 |
9 | J, j | 74 | 0x4A | 106 | 0x6A |
10 | K, k | 75 | 0x4B | 107 | 0x6B |
11 | L, l | 76 | 0x4C | 108 | 0x6C |
12 | M, m | 77 | 0x4D | 109 | 0x6D |
13 | N, n | 78 | 0x4E | 110 | 0x6E |
14 | O, o | 79 | 0x4F | 111 | 0x6F |
15 | P, p | 80 | 0x50 | 112 | 0x70 |
16 | Q, q | 81 | 0x51 | 113 | 0x71 |
17 | R, r | 82 | 0x52 | 114 | 0x72 |
18 | S, s | 83 | 0x53 | 115 | 0x73 |
19 | T, t | 84 | 0x54 | 116 | 0x74 |
20 | U, u | 85 | 0x55 | 117 | 0x75 |
21 | V, v | 86 | 0x56 | 118 | 0x76 |
22 | W, w | 87 | 0x57 | 119 | 0x77 |
23 | X, x | 88 | 0x58 | 120 | 0x78 |
24 | Y, y | 89 | 0x59 | 121 | 0x79 |
25 | Z, z | 90 | 0x5A | 122 | 0x80 |
When the firmware receives a message command on the NUS Bluetooth service, it will call the abc_display_char()
function to display that character's LED. The abc_display_char()
function takes an input character, calculates the corresponding LED index, and turns that LED on for a certain duration (g_char_duration_ms
)—then turns the LED off in preparation for displaying the next LED/letter (g_inter_char_duration_ms
).
// In Nordic UART Service Handler...
// Display message received
if (p_data[0]==HEAD_MESSAGE_0 && p_data[1]==HEAD_MESSAGE_1) {
for (uint8_t ii=0; ii < length-2; ii++) {
char cc = p_data[ii+2];
if (abc_validate(cc) == true) {
// NRF_LOG_INFO("%c", cc);
abc_display_char(cc);
}
}
eg_leds_off();
}
...
void abc_display_char(char c) {
// If character is a space, turn off LEDs for g_space_duration
if (c == ' ') {
clear_leds();
nrf_delay_ms(g_space_duration_ms);
}
// If character is ABC, display character LED for g_char_duration and inter-character delay with LEDs off
else {
uint8_t led_idx;
if (c >= 'A' && c <= 'Z') {
led_idx = c - 'A';
eg_set_single_led(led_idx, g_led_r, g_led_g, g_led_b, LED_DIN_PIN);
nrf_delay_ms(g_char_duration_ms);
clear_leds();
nrf_delay_ms(g_inter_char_duration_ms);
} else if (c >= 'a' && c <= 'z') {
led_idx = c - 'a';
eg_set_single_led(led_idx, g_led_r, g_led_g, g_led_b, LED_DIN_PIN);
nrf_delay_ms(g_char_duration_ms);
clear_leds();
nrf_delay_ms(g_inter_char_duration_ms);
}
}
}
The firmware sets the following default LED color/brightness values and on/off durations in milliseconds. These parameters can be easily changed to reduce the brightness, change colors, or slow down the message display.
#define DEFAULT_LED_R 255
#define DEFAULT_LED_G 255
#define DEFAULT_LED_B 255
#define DEFAULT_CHAR_DURATION_MS 1000
#define DEFAULT_INTER_CHAR_DURATION_MS 250
#define DEFAULT_SPACE_DURATION_MS 1000
uint8_t led_idx; // LED index number (range 0-25)
uint8_t led_r, led_g, led_b; // LED RGB color (range 0-255)
uint16_t char_duration; // Sequence LED on duration (ms)
uint16_t inter_char_duration; // Sequence LED off duration (ms)
uint16_t space_duration; // 'Space' character duration (ms)
Apologies for the user interface design... I didn't spend much time on it so it is purely functional (not pretty). The app has four main sections that are accessible via the bottom tabs. Wall lets you interact with the alphabet lights in real-time; pressing a letter in the app will illuminate the corresponding letter in the frame. Message lets you input a text string to display letter-by-letter like in the television show. The function iterates over the character array and activates the corresponding LED in a timed sequence. Light Patterns contains some easter eggs to recreate the messages from the show ("right here", "run") and some other fun things like a random yes/no Magic 8 Ball. Settings gives you full control to monitor the battery level and adjust the timing and LED color/brightness settings. Using max brightness white is easiest because the light bulbs are already tinted.
The mobile app was written in Javascript using React Native and the react-native-ble-manager library. Button onPress events can simply use the sendWallMessage()
function to trigger the lights sequence.
export const sendWallMessage = (peripheralId, text) => {
var data = [bleConst.HEADER_MESSAGE[0], bleConst.HEADER_MESSAGE[1]];
for(var ii = 0; ii < text.length; ii++) {
var val = text.charCodeAt(ii);
data.push(val);
}
writeEllieChar(data, peripheralId, bleConst.EG_UART_SERVICE_UUID, bleConst.EG_UART_RX_CHAR_UUID);
};
...
// Usage Examples:
actions.sendWallMessage(CONNECTED_PERIPHERAL.id, 'A')
actions.sendWallMessage(CONNECTED_PERIPHERAL.id, 'hello world')
actions.sendWallMessage(CONNECTED_PERIPHERAL.id, this.state.text)
The firmware also includes a few easter egg references from the Stranger Things show. Calling these commands will also display a colorful blinking light sequence at the end to mimic the "RUN" scene from the television show.
void stranger_things_easter_egg_0(void) {
abc_display_string("right here");
eg_leds_off();
}
void stranger_things_easter_egg_1(void) {
abc_display_string("run ");
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
all_leds_blink(g_led_r, g_led_g, g_led_b, 100, 100);
theater_chase_rainbow(25);
eg_leds_off();
}
Position the Christmas lights strands against the wallpaper plywood to align with the letters and match the configuration of the real Stranger Things wall. Use super glue for a more secure and permanent bond.
Fold the wires around to the backside of the plywood and insert into the frame. Secure with the frame tabs and clear room for any wall-mounting hardware.
Connect the light strands together with the extension cables and plug it into the electronics board. Connect the battery or power the board via USB cable.
Launch the mobile app and establish a Bluetooth connection. Then use the various tab options to send a message.
The primary motivation for this project was to be a gift for my friend and coworker, Regina. A few months prior, she had a hemorrhage that required multiple brain surgeries. She experienced paralysis on the right side of her body and had some difficulty speaking. We were both fans of the Stranger Things show and joked that she resembled one of the main characters (Eleven) with her shaved head and slow speech. I had previously worked on a project with her that utilized electronics and a mobile app to control addressable LEDs, so the inner workings were already familiar to me. In fact, I was able to use old prototype hardware.
I was compelled to build this project because I felt that it was a gift that only I could give—and if I didn't, she would never receive something so special. I'm happy to report that she is doing well 2 years later, continuing her recovery with the best of spirits and brightest of smiles.
I also added a nameplate with a custom message on the back of the frame. The nameplate itself was a small sheet of anodized aluminum, which could easily be engraved by the laser. It turned out great.