Build a programmable light display on Raspberry Pi

Celebrate the holidays or any special occasion with a DIY light display using a Raspberry Pi, Python, and programmable LED lights.
81 readers like this.
4 hot skills for Linux pros in 2017

Internet Archive Book Images. Modified by Opensource.com. CC BY-SA 4.0

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.

Prerequisites

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

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[19] = (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

  1. 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).
  2. Install the 74AHCT125 level converter chip, light, power supply, and Pi according to this schematic:

  3. String additional lights to the first light using their connectors. Note the total number of lights.
  4. Plug the power supply into the wall.
  5. 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

The 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 neopixel.GRBW.

The run_lights.py script

The 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 static.

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

The 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.

The current state and three front-end buttons use JavaScript to interact with a set of REST API endpoints presented by the Flask application:

  • /api/v1/state: Returns the current state of the shared state file, which defaults to static if 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:

  • launch_christmas.sh
  • launch_new_years.sh

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):

./launch_christmas.sh

You can turn off the lights and stop run_lights.sh and the Flask application by using lights_down.sh.

The code for the library and the flask application are in the Raspberry Pi Neopixel Controller GitHub repository.

What to read next
User profile image.
My primary experience is in using programming to provide industrial strength solutions to problems experienced by researchers in conducting their research endeavors.

2 Comments

This reminds me of the ancient time when I made a "color organ" -- a device that takes the sound of a hifi system, then uses 3 frequency ranges to control lights - red, green, and blue (regular incandescent bulbs - LEDs hadn't been invented yet). This involved starting with a bare circuit board, and basic electronic parts, including triacs for controlling the 3 circuits.

Very nice and simple project. Perfect for hollidays

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.