A few months back, a $3000 thunder and lightning mood lamp went viral in the maker community. It was a stunningly beautiful light, but the price tag left it out of the reach of anyone with their sanity intact. What we'll make today isn't exactly the same - we're making something more practical, instead of an art piece, but it's going to be a whole lot cooler and more customizable.

I've chosen to omit speakers on the assumption that you probably already have a good pair of speakers in your room which you'd rather use, and frankly putting a speaker in a lamp is kind of weird. Instead, I'll be adding a microphone that will allow the lightning to react automatically to loud noises - either from an actual thunderstorm, or a soundtrack played from your PC or stereo.

We're also going to use a strand of full RGB Neopixel LEDs (WS2812B), so we can reproduce colours other than white and have control over every pixel.

Warning: the power supply I've used in this project has screw terminals that connect to a live AC wire. If you don't feel confident wiring a plug, please ensure you buy a fully enclosed power supply. At the very least, you'll need to enclose the PSU within a secure project box.

Step 0: Introduction

http://www.youtube.com/watch?v=-uoMIdDy9Fo

Here's a demo video of the finished project. I've implemented a few different modes so far, from the standard lightning to a trippy acid cloud and a colour fading mood lamp, which can be chosen from the remote control.

The full code and libraries needed are available for download from this Github repository.

Step 1: You Will Need

  • WS2812B strand, typically priced at about $50 for 5 metres. Don't worry if you have another type of Neopixel strand, it's almost certainly supported by the FastLED interface, but your wiring may be different (you may require a sync line in addition to the signal, for example).
  • 5V, 10A+ power supply - I bought some 15A units for $11 each. They take 120-240V AC input, and produce a hefty 5V output which will be more enough to power all our pixels at full brightness, and the Arduino.
  • Electrical cabling, plug and inline switch
  • Project enclosure
  • Two Arduinos. $10 Funduino clones are fine. The second is necessary for remote control, while the first controls the main logic and LEDs.
  • Two 2.2k (or thereabouts) Ohms resistors - the exact value doesn't matter so much, around 1.5k up to 47k should work.
  • Breadboard
  • TSOP4838 IR receiver
  • IR remote - I bought in bulk for about $2 each, but any remote should work with code modifications.
  • Large microphone module
  • Scrap MDF wood to cut your base from, and a jigsaw.
  • Polystyrene packing material / box inserts.
  • Polypropylene cotton pillow stuffing. I pulled more than enough from a few horrible old cushions. If thats not an option, you should be able to buy some new for about $10, or use even cheaper cotton wool. I tried with both - the cotton wool needed more work in having to tease it out and wasn't as fluffy, but in a pinch, it will work.
  • Chain and hooks to hang the cloud - should hold up more than 5kg.
  • Glue gun with low temperature setting
  • Spray glue - easier to stick the stuffing onto your cloud with this, but a glue gun could also work.

The total cost is around $100 not including tools, but most of this I scrounged from around the house. All of the electronics components are commonly available; the microphone can be found in a sensor kit or bought individually.

Step 2: Cut the Base

Cut out a rough base from a scrap piece of MDF with a jigsaw - the exact shape is obviously up to you, but for some reason a cloud is kidney-bean shaped in my mind. We'll be attaching some hooks into this for hanging, but otherwise it just provides a solid base to build on. The central area will be reserved for the electronics, PSU and to hand the chain from, so ensure you have enough space to place at least your project enclosure with some hooks surrounding it. 

Step 3: Layer on Polystyrene

This is most difficult and creative step, but we're really just creating something solid and kinda-sorta cloud-shaped to glue the LED strip onto. Glue large pieces of polystyrene packing on to the base (and under it), using a low heat setting on your glue gun. If you don't have a low setting, turn off the heat gun and let it cool a little before attempting to glue. If the temperature is too high, you'll simply melt through the packing material.

Ensure each piece is solid before gluing the next, and it's best to stick more on than not enough.

Again, remember to leave a large enough cavity inside the cloud to fit the electronics, chain and hooks.

Step 4: Carve a 3D Cloud Shape

Use a carving knife to neaten up your cloud by rounding off the corners and cutting unnecessary material away, until you've achieved a rough 3D cloud shape. It doesn't really matter how rough this is since we'll be covering everything in stuffing later – you can easily hide mistakes.

Step 5: Fix Hooks, Tidy Up

Finally, fix three or four hooks to the MDF base, from inside each corner of the cavity of the cloud. You'll need to drill a small pilot hole as MDF is difficult to screw straight into.

I also gave everything a simple coat of white spray paint to ensure a uniform colour base, but I'm not sure it was actually necessary.

Step 6: Glue LED Strips

Before you begin applying glue to the LEDs, either start from a new strip or count how many LEDs you have in total - you'll need to work out how many you've used later in the programming step. Cut a small hole in the side of your cloud and poke through the wires that make up the beginning of your LED strip into the cloud cavity. Be very careful that you're starting from the correct end - the LED strips are direction sensitive, so ensure the signal arrows point away from the cavity.

Working slowly, stick the LED pixels to the polystyrene base in a circular pattern, before pulling the strip down to the base to cover the underside. Again - you don't need to be perfect here, because once we've diffused everything and smothered it with stuffing, it all looks rather stunning anyway.

I used a total of 85 LEDs, or just over 2.5m, having encircled the main body twice and used a single string of LEDs on the underside.

Step 7: Wiring Diagram

The wiring is complex, but easily broken down into sections.

First, get the power supply wired in and secured, preferably in a separate project case. I'm not going to lecture you on the safety of live AC wires, so I'm going to assume you can handle this part, and you have a 5V and GND line from it.

IMPORTANT: when programming and testing the Arduino, the 5V from your power supply should remain isolated from the Arduino's (the GNDs are all connected, though) - it should only be powering the LED strip, while the Arduino uses the 5V supplied over USB. When you're done programming, the USB should be disconnected, and will no longer provide 5V to the Arduino - at this point, you should connect the 5V from your supply to the 5V rail on the left side of the breadboard.

Start by connecting the ground and 5V pins from each Arduino to the left side rails of the breadboard. They will share the same power source, whether that's the external PSU we have or USB plugged into one of them.

Next, complete the I2C wiring section - this is what allows our two Arduinos to communicate. Take the A4 pins from both Arduinos onto a single row on the breadboard, then connect a 2.2k resistor from that row to 5V rail. Repeat for A5, connecting them on separate row, with another 2.2k resistor again to 5V.

Connect the IR receiver next - check pin configuration if you have another model, but basically the signal pin should go to D11 on one Arduino. Upload the thundercloud_ir_receiver.ino sketch to this Arduino (all code here), then unplug the USB since we no longer need it.

On the other Arduino, connect the Data In signal pin from the start of your LED strip to D6. The GND from your LEDs should be common with all Arduinos, but at this point the 5V will come directly from the PSU.

Also on this Arduino, plug the microphone module into A0. Upload the other thundercloud.ino sketch, and keep the USB plugged in for now while you debug. Begin by changing the NUM_LEDS variable appropriately.

Step 8: Glue on the Stuffing

As a final step, glue on your stuffing. There's no particular technique here – just spray the cloud with a layer of glue and grab a handful of stuffing on. It's easier to work with stuffing if you've already teased it out to increase the surface area, though.

If you've used the same remote as I did, the STROBE button puts it into sound reactive cloud mode; FLASH is the trippy colour mode, and FADE is the slow fading colour mood lamp.

Step 9: Code Explanation

Why two Arduinos? Both the infrared receiver programming and the WS2818B pixel driver library are very sensitive to timing - if the timing is delayed, the IR signal is corrupted. By giving each circuit it's own micro controller and letting them to talk over the I2C protocol, we can ensure timing is perfect on each. You may also find separate IR modules with their own micro controller built-in, but my research found those actually cost more than a simple Arduino clone and IR LED. The thundercloud_ir_receiever shouldn't require explanation, though you may want to read up on I2C basics first.

On the main thundercloud controller, we define different operating modes, such as ON (the lightning effects are not sound activated), CLOUD (the lightning is sound activated only), ACID (the cloud shows trippy colours), or simple single colour modes. To define a new mode, add to the enum first, then open up the console and find a remote control button to map it to - each remote press should print a line of debug. In the receiveEvent() method, we map those key presses to a mode, so add an additional switch statement there. Finally, in the main loop() method we route those mode selections to different display functions.

The microphone smoothing code is originally from Adafruit - I simplified it for our needs, and added a trigger when a louder than average noise is heard.

Step 10: Lightning Modes

The lightning displays combine three different "types" of lightning to achieve something sufficiently realistic, or at least pleasing to the eye. The first type is crack(), where every LED is briefly turned on for between 10-100ms. The second type is rolling() -  where each LED has a 10% chance of activating, and the entire loop is repeated 2-10 times, with a 5-100ms delay between each cycle. The third type is thunderburst(), which picks two different sections of the strip, each between 10-20 LEDs, flashes these sections briefly from 3-6 times. Examine these methods in detail to see how individual LEDs are activated - the HSV colour wheel is used throughout (so white is H=0,S=0,V=255). I'd encourage you to tweak or write new lightning displays, then share them in the comments if you make one you like.

Each time lightning is triggered or the loop is run, the cloud randomly chooses between the three types of lightning. Finally, a reset() method turns off all the lights, otherwise they'll "remember" their previous state.

Questions or problems - please get in touch in the comments and I'll do my best to help. If you have a Github account, feel free to post bugs or problems to the issues tracker instead. If you've made any modifications or written some new lighting functions, please share a link to your code on Gist or Pastebin.