Introduction: WiFi Connected LED Bars With Shared Animations

About: A Maker since childhood with all the classic symptoms, a robot builder, and an Internet software CTO/Tech Product Manager.

This project explores the ability to have LED bars with an animation that hands off from one bar to the next. They are WiFi connected, so the bars can be anywhere in the world, and the animation will move between them, creating a shared experience over distance. They can also be used in one location to avoid the need to run LED signal wiring between them - each bar only needs a wall adapter to work.

These bars use Particle Core and Photon processors and WS2812b LEDs. The concern was that handing off an animation from one bar to the next would take too long, but the Particle.io Publish and Subscribe system worked fast enough for basic animations.

Step 1: Parts

The following parts were used in the project for each strip:

  • A non-waterproof WS2812b LED strip. I used 30/meter. The non-waterproof ones usually have double-sided tape already attached to them so they are easy to mount. You will need 1 meter per channel since the channels are a meter long. The link above is for one meter, but you can also get 5m strips and cut them up if you are making several. More LEDs per meter is fine - just make sure to get a correspondingly large power supply. Each (5050) LED in these strips can use up to 60ma when fully on.

Step 2: Attaching the Box to the Strip

To house the CPU, I used a small project box at the end of the strip. I did try a center-mount option (more info later), but the one on the end looks the best. To connect the project box to the strip, use a 6" piece of the 1/2" wide by 1/16" thick aluminum bar to run between the box and the strip. The bar is mounted on the bottom of the box so that the lid can be removed and replaced easily.

The box will need two holes to be drilled in it. The first is for the panel mount power jack. That should be centered on the outside end of the box, maybe a bit closer to the lid without hitting it to give a bit more room for the CPU. I used a step drill to get the hole to match the size of the jack. A step drill is really the best and safest way to drill larger holes like this.

On the other side of the box, you need a small hole to allow 3 wires to run from the controller to the strip. You can set the box and aluminum channel with the end cap with the hole on a table to get the right height for the hole.

Once the two holes are all set, the next step is to prep the LED strip.

Step 3: Wiring the Strip

The LEDs will be supplied with 5v dc. The CPU will also have 5v, but it is a 3.3v device and has an internal regulator. The trick is that the data line from the CPU to the LED strip will be at 3.3v, and the LEDs might work, but sometimes will flicker since that voltage is a bit low per the LED spec. An extended discussion is in a previous Instructable.

For this project, we will keep the 5v supply, and not modify the colors to control current usage. You could use a level shifter, and there is more info later on how that looks.

For this project, though, the new trick is to use a diode to drop the voltage to the first LED slightly, and then use that one to drive the rest of the strip. This "sacrificial LED" approach is discussed here and here. Note that we will still be using that first LED, but it will be very slightly dimmer - mostly unnoticeable. This is a very compact solution to the problem, and only requires a single diode to work.

So, for this strip, we will cut the first LED off the strip and separate that first one from the rest by a short distance. The Data and Gnd wires will simply have a jumper across that gap. Then the +5 red wire will be connected to the second LED with a diode connecting back to the first LED. In that way, the first LED will have 5v - ~0.8v (diode forward voltage) = ~4.2v as the supply, which is within the 70% recommendation for the LED for the data vs power lines. That first LED will pass the data to the rest at that ~4.2v, so all the rest can run at 5v.

This approach leaves that short gap distance between the first and second LEDs so they are not spaced exactly the same as the others. It's not very obvious unless you are looking for it. I think this is the easiest way to wire it, but I did try a different approach. For that, I cut off a slice from the end of the first LED so that there was still a gap, but the LED to LED spacing would remain. That one requires the Gnd and Data lines to have a jumper from the front of the first LED to the second, so it's a bit more wire, but does work - see the pictures for that.

Once that is complete, the LED can be placed in the channel.

The LED strip should have double sided tape on it so that it can be mounted to the channel. Test fit it first to get the position just right - you will need a small amount of room at the end for the end cap. Putting a small piece of tape under the first couple LEDs where you soldered the wires will insulate the soldering joints just in case. Make sure to have the input side of the LED strip next to the box where the controller will be.

You can now add the cover and end caps, but since they slide on, you only need the end cap with the hole for now. The box can now be attached to the channel with the 6" piece piece of aluminum bar. Cut a 6" piece of double sided foam tape and attach it to the bar. I cut a notch in the tape where the box has a ridge on the edge (see pictures). Run the wires into the box, and mount the box to the channel.

I used a label maker to make a small 5v label under the jack to avoid future confusion.

Step 4: Wiring the CPU

The are two ways to attach the connectors to the controller board. One is to solder the wires directly to the board for a fairly permanent project. You can also solder push connectors on the end, and just push those on the header pins on the board.

The power jack +5 and Ground are connected to the strip power, and the controller power. If you use a different controller, make sure it accepts a 5v power source. It is best to add a capacitor to the power source - something like a 1000 uf electrolytic one. This is recommended for the LEDs since they can be susceptible to power surges from the wall adapter. On the power jack I had, the longer pin was the outside ground. It's worth confirming that with yours.

The final connection is from the controller data out pin to the data in pin on the LEDs strip. I used a 330 ohm resistor in series with that connection to reduce noise in the line. The use of the capacitor and resistor is noted in many of the LED project sites like the Adafruit NeoPixel Überguide.

Step 5: Programming

The following code was used in the video in the Introduction step. It was a basic test of moving a dot between three of the bars. It's mostly a copy of the sample code and is not very elegant.

In the Setup function, we Subscribe to the led_mesh_handoff message that will come from the other LED strips. Now whenever another strip publishes that message, the myHandler function will run.

In the Loop, the basic idea is that the dot_pos variable will step from 0 to 29 (30 LEDs in the strip). When it hits the end, it will Publish a message for the next strip. That message is the id of the next strip, and for the sample code, this was the middle strip (#2), so the next one is #3, or "003". If dot_pos = 255, then we are just waiting.

In the message handler for messages received, we simply check to see if the id is for us (in this case #2, or "002"), and if so, set the dot_pos to zero for the Loop to move along.

That's it - very simple, and you can see how easy Publish and Subscribe can be.

This code is very simple - the hard coded IDs need to be changed for each strip, which is not hard, and the advantage is that they will always be in the same order. Another approach would be to have them auto-discover each other, but that will take more code to deal with timing issues. Another Instructable!

* This is a minimal example, see extra-examples.cpp for a version
* with more explantory documentation, example routines, how to * hook up your pixels and all of the pixel types that are supported. * */

#include "application.h" #include "neopixel/neopixel.h"

SYSTEM_MODE(AUTOMATIC);

// IMPORTANT: Set pixel COUNT, PIN and TYPE #define PIXEL_PIN D2 #define PIXEL_COUNT 30 #define PIXEL_TYPE WS2812B

uint8_t dot_pos = 0; uint16_t wait = 50;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

void setup() { strip.begin(); strip.show(); // Initialize all pixels to 'off' Particle.subscribe("led_mesh_handoff", myHandler);

} void loop() { uint16_t i, j; if (dot_pos != 255) { for(i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, 0, 0, 0); } strip.setPixelColor(dot_pos, 0, 127, 127); strip.show(); dot_pos++; if (dot_pos == PIXEL_COUNT) { strip.setPixelColor(dot_pos-1, 0, 0, 0); strip.show(); delay(wait); Particle.publish("led_mesh_handoff","003"); dot_pos = 255; //delay(1000); } else { // delay if we are not switching to a new strip delay(wait); } } } // loop

// Now for the myHandler function, which is called when the cloud tells us that our buddy's event is published. void myHandler(const char *event, const char *data) { // Spark.subscribe handlers are void functions, which means they don't return anything. // They take two variables-- the name of your event, and any data that goes along with your event. // In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken" // // Since the input here is a char, we can't do // data=="intact" // or // data=="broken"

// chars just don't play that way. Instead we're going to strcmp(), which compares two chars. // If they are the same, strcmp will return 0. if (strcmp(data,"002")==0) { dot_pos = 0; }

//if (strcmp(data,"intact")==0) { // if your buddy's beam is intact, then turn your board LED off //digitalWrite(boardLed,LOW); //} //else if (strcmp(data,"broken")==0) { // if your buddy's beam is broken, turn your board LED on //digitalWrite(boardLed,HIGH); //} //else { // if the data is something else, don't do anything. // Really the data shouldn't be anything but those two listed above. //} } // myHandler

Step 6: Level Shifter Variant

The first prototype of this project used an SN74HCT125N level shifter to make the 3.3v LED data wire control from the Spark Core up to 5v that the LED strip is looking for. In the end, this larger box and parts were not needed, but the build pictures may be useful for other projects that need more circuitry in the box. I used a wider bar and cut it into a shape that matched the box and strip.

Step 7: Trinket Variant

You can also use a small controller without Wifi, like the Adafruit Trinket. The mounting and connections are about the same, and the idea is to just have a fixed pattern running for holiday or party lighting that can be easily moved and setup. The channels come with mounting clips to make seasonal setup easier.

You could add a switch to change the lighting modes. See the next step for an example.

Step 8: Mounting in the Middle Variant

One other test was to mount the box in the middle of the strip to keep the ends clear. In the pictures the box is also painted white (did not get around to painting the lid). To run the wires, a hole was drilled in the strip and the middle of the box bottom. The power wires can just be connected to the LED strip in the middle, and the data wire is run along the side to the start of the strip. I can't say this is a great place to mount the box - perhaps in certain situations it would make sense.

The picture also shows a button, which is not connected, but could be used to switch modes or something.

Internet of Things Contest 2017

Participated in the
Internet of Things Contest 2017

Lights Contest 2017

Participated in the
Lights Contest 2017