Introduction: WiFi Mesh Synchronized LED Bars
This project is a collection of LED bars with individually controllable digital LEDs (WS2812b "Neopixels"). They allow animations to be done across them without wiring them together. They use a WiFi Mesh to connect to each other, and the animation adapts to having more or less bars in the mesh.
The inspiration was for a pair of drum majors to have decorated maces/batons for a Christmas parade. The LED animation between them is synchronized. The LEDs could also be strands instead of strips.
The other use is for an LED art installation where you do not want to run a data wire between all the LEDS around a room - all they need to do is be plugged in individually.
For this project, they are not connected to the Internet. They set up their own private WiFi access points and web servers. So, this project is not dependent on external networking, and can run in remote locations. They run on 5v, so can easily be powered by external cell phone batteries!
Step 1: Parts
The following parts were used in the project for each strip:
- A non-waterproof WS2812b LED strip. I used 30 LEDs/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. 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.
- Plastic electronic project enclosure 60x36x25mm - this one is small enough to hold a D1 Mini.
A 5v power supply - a 2 amp one should be fine with 30 LEDS @ 0.06 amp each when full on.
A USB to 5.5mm x 2.1mm cable if you would like to power this project from a USB battery
- A D1 Mini ESP8266 board - also available for less, but with a longer wait.
- Aluminum channel with cover and end caps for LED strips. There are many profiles to choose from. This one is wide enough for the WS2812b LED strips (12mm), and low profile.
- Aluminum bar - the channel is 17mm wide, so a 1/2" wide aluminum bar is a good size. It should be 1/16" thick and 6" long for each bar you make.
- Double sided foam tape - 1/2" wide.
- 1000uF capacitor - recommended for each strip, to help prevent voltage spikes from damaging the LEDs.
- Hookup wire. This 26 gauge silicone wire is very flexible and helps keep the wire from pulling the soldering pads off the LED strip. It also does not melt when you touch it with the soldering iron. I have also used servo wire which is also very flexible, but silicone wire is my new favorite wire. You will only need abot 6" of each color (red, black, yellow).
- Jumper wires - the female red, black, and yellow are used to connect to the CPU. You could skip these and solder the hookup wire directly to the board if you are the confident sort.
- A 330 ohm resistor to reduce noise in the LED strip data line.
- A 1N4448 Signal Diode or similar to allow the 3.3v processor to reliably drive the 5v LED strip.
- 3mm heat shrink tubing - you will only need about 5" of it.
Step 2: Build the Bars
The construction for the bars is the same as in this previous Instructable. There are similar step-by-step pictures here from a recent build, and the discussion can be found on that other Instructable.
One new tip on sticking the LEDs down to the aluminum channel: Sometimes the double-sided tape on the LED strips is slightly shorter than the LED circuit board and you will see a slight buckle in the LED strip. If you simply cut the tape at that location, it will lay down flat.
I also used some drops of UV glue to lock down the power wire and any parts of the LED strip that did not stay down.
Instead of the Particle Photon controllers, this project used used WeMos D1 Mini boards, also based on the ESP8266 chip set. These are nice and small for an LED project. I used male headers to allow room for the female jumpers. Reversing the connectors will not fit in the enclosure. This approach is also easy to solder. I have also used 20 gauge solid core wire with crimped on female connectors, and that works too, but is more effort.
These bars use the same sacrificial LED approach for the first LED. In practice, it really is not noticeable. Also, the slight gap between the first two is also almost unnoticeable
If you intend to use the clips to mount the aluminum channel, the aluminum bar connecting the channel to the project box may get in the way for directly mounting the clips to a wall, so you may need to put some washers or a loose nut under there to stand them off by 1/16".
Step 3: Mesh Code
Each of the LED bars is running the same code. The basis of this project is the painlessMesh Library at https://gitlab.com/BlackEdder/painlessMesh. That library handles most of the low level work of establishing Access Points, Web Servers etc. Each bar is a mesh node.
The mesh has one controller, and animation change notices are broadcast to all the nodes/LED bars. For a large mesh, there could be some latency in the messaging, but for the scale I was working, it was not noticeable.
On startup, the node assumes it is the controller, but then the changedNodes message triggers an evaluation. The lowest # chip id in the mesh becomes the controller. This usually takes a second or two for all the nodes to settle down and assume a single controller. You could put more effort into re-synchronizing faster (mid-animation), but those change messages are fairly chatty, so it takes a bit for the network to settle down anyway. In practice, once they re-synch, they stay very solid.
For animations that cross bars, the code gets a list of the nodes, sorts it, then only draws if the current node is the one being drawn. They sort in chip id order, so you can do animations that will be consistent, no matter when they start up. Also, the animations will adapt to nodes being dropped.
The animation code appears in three places. The first is the receivedCallback function, where the bar has received a new animation command. This is fairly simple - just sets the timing step size for the animation and resets the counters. The second place is in the loop function. In there, the code checks to see if the current animation is done, and moves to the next step. The final place for animation code is the stepAnimation function, where all the drawing is done.
The system uses the millis timer to update - avoiding the use of the delay function since it blocks some of the libraries. The millis code should rollover correctly.
Note that I had issues with the NeoPixel library and painlessMesh with more than one LED, so I switched to FastLED.
Here is the code on GitHib, and it is also attached here. You pretty much load it on all the bars and you are ready to go on LED animation coding!