This past holiday season, I decided to add some extra joy to our house by setting up a DIY light display. I used a Raspberry Pi, a programmable light string, and Python.
You can set up your own light display for any occasion, thanks to the flexibility of the WS12911/2 (or NeoPixel) system, by following these directions.
You will need:
- 1 – Raspberry Pi with headers and an Ethernet or WiFi connection. I used a Raspberry Pi Zero W with headers.
- 1 – WS12811/2 light string. I used the Alitove WS2811 Addressable LED Pixel Light 50, but many other types are available. Adafruit brands these as NeoPixel.
- 1 – 5v/10A AC-DC power supply for WS12811 if you use the Alitove. Other lights may come with a power supply.
- 1 – Breadboard
- 2 – Breadboard-to-Pi-header jumper wires. I used blue for the Pi GPIO pin 18 and black for the Pi ground.
- 1 – 74AHCT125 level converter chip to safely transmit Pi GPIO wire signals to 5v/10A power without feeding back to the Pi.
- 8 – Breadboard-to-breadboard jumper wires or solid-core 24 AWG wires. I used red/orange for 5v power, black for ground, and yellow for data.
- 1 – SD card with Raspberry Pi OS installed. I used Raspberry Pi OS Lite and set it up in a headless mode with SSH enabled.
What are WS2811/2 programmable LEDs?
The WS2811/2 class of programmable lights integrates red, green, and blue LED lights with a driver chip into a tiny surface-mounted package controlled through a single wire.
Each light can be individually programmed using an RGB set of integers or hex equivalents. These lights can be packaged together into matrices, strings, and other form factors, and they can be programmatically accessed using a data structure that makes sense for the form factor. The light strings I use are addressed using a standard Python list. Adafruit has a great tutorial on wiring and controlling your lights.
Control NeoPixel LEDs with Python
More on Raspberry Pi
Adafruit has created a full suite of Python libraries for most of the parts it sells. These are designed to work with CircuitPython, Adafruit's port of Python designed for low-cost microcontroller boards. You do not need to install CircuitPython on the Raspberry Pi OS because the preinstalled Python 2 and Python 3 are compatible.
You will need to
pip3 to install libraries for Python 3. Install it with:
sudo apt-get install python3-pip
Then install the following libraries:
Once these libraries and their dependencies are installed, you can write code like the following to program one or more lights wired to your Raspberry Pi using
sudo python3 (sudo is required):
import board import neopixel num_lights = 50 # program 50 lights with the default brightness 1.0, and autoWrite true pixels = neopixel.NeoPixel(board.D18, num_lights) # light 20 bright green pixels = (0,255,0) # light all pixels red pixels.fill((255.0,0)) # turn off neopixels pixels.fill((0,0,0))
Set up your lighting system
- Install the SD card into the Raspberry Pi and secure it, the breadboard, and lights where they need to be (velcro works for the Pi and breadboard).
- Install the 74AHCT125 level converter chip, light, power supply, and Pi according to this schematic:
- String additional lights to the first light using their connectors. Note the total number of lights.
- Plug the power supply into the wall.
- Plug the Raspberry Pi power supply into the wall, and wait for it to boot.
Install the light controller and Flask web application
I wrote a Python application and library to interact with the lights and a Flask web application that runs on the Pi. See my Raspberry Pi Neopixel Controller GitHub repository for more information about the code.
The lib.neopixc library
lib.neopixc library extends the
neopixel.NeoPixC class to work with two 50-light Alitove light strands connected in serial, using a programmable list of RGB colors lists. It adds the following functions:
set_color: Takes a new list of lists of RGB colors
walk: Walks through each light and sets them to the colors in order
rotate: Pushes the last color in the list of lists to the beginning of the list of lists for blinking the lights
If you have a different number of lights, you will need to edit this library to change the
self._num_lights value. Also, some lights require a different argument in the order constructor attribute. The Alitove is compatible with the default order attribute
The run_lights.py script
run_lights.py script uses
lib.neopixc to support a colors file and a state file to dynamically set how the lights behave at any time. The colors file is a JSON array of arrays of RGB (or RGBW) integers that is fed as the colors to the
lib.neopixc object using its
set_colors method. The state file can hold one of three words:
static: Does not rotate the lights with each iteration of the while loop
blink: Rotates the lights with each iteration of the main while loop
down: Turns all the lights off
If the state file does not exist, the default state is
The script also has HUP and INT signal handlers, which will turn off the lights when those signals are received.
Note: Because the GPIO 18 pin requires sudo on the Raspberry Pi to work, the
run_lights.py script must be run with sudo.
The neopixel_controller application
neopixel_controller Flask application, in the neopix_controller directory of the github repository (see below), offers a front-end browser graphical user interface (GUI) to control the lights. My raspberry pi connects to my wifi, and is accessible at raspberrypi.local. To access the GUI in a browser, go to http://raspberrypi.local:5000. Alternatively, you can use ping to find the IP address of raspberrypi.local, and use it as the hostname, which is useful if you have multiple raspberry pi devices connected to your wifi.
/api/v1/state: Returns the current state of the shared state file, which defaults to
staticif the state file does not exist
/api/v1/blink: Sets the state file to blink
/api/v1/static: Sets the state file to static
/api/v1/down: Sets the state file to down
I wrote two scripts and corresponding JSON definition files that launch
run_lights.py and the Flask application:
These can be launched from a command-line session (terminal or SSH) on the Pi after it is set up (they do not require sudo, but use sudo internally):
You can turn off the lights and stop
run_lights.sh and the Flask application by using
The code for the library and the flask application are in the Raspberry Pi Neopixel Controller GitHub repository.