WS2811 Notes

2 minute read

I know, I’m late to the WS2811 party. But better late than never ;-) During the Christmas period of the wonderful year 2020, we decided to make a “Happy New Year” sign … with a lot of colorful lights. WS2811 to the rescue!

Setup

I decided to go with a Raspberry Pi as the computing platform, because it’s a bit more luxuriuos in comparison to a real real-time platform such as Arduino ;-)

Hardware

One downside of using a Raspberry Pi is that its IO pins are 3.3V and WS2811 requires 5V. Now, it can work, and in all honesty, simply hooking up a 50 LED string to a Pi did work out for me on the first try. But before moving our project off the workbench into the real world, I’ll probably introduce a 74AHCT125 to convert the level.

For now, I simply connected a 5V power supply to the ledstring, connected the ground signal to the Pi’s ground and hooked up the data signal wire to GPIO18. Little magic there.

Software

Thanks to the Adafruit CircuitPython NeoPixel library, NeoPixels or WS2811/WS2812 LEDs can be controlled directly from your Raspberry Pi using Python!

$ sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel
$ sudo python3 -m pip install --force-reinstall adafruit-blinka

First Experiments

$ sudo python3
Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import board
>>> import neopixel
>>> pixels = neopixel.NeoPixel(board.D18, 50)
>>> pixels[0] = (255, 0, 0)
# rainbow.py - the obligatory RGB led showcase ;-)
import time
import board
import neopixel

pixel_pin = board.D18
num_pixels = 50
ORDER = neopixel.GRB
pixels = neopixel.NeoPixel(
  pixel_pin, num_pixels, brightness=0.2, auto_write=False, pixel_order=ORDER
)

def wheel(pos):
  # Input a value 0 to 255 to get a color value.
  # The colours are a transition r - g - b - back to r.
  if pos < 0 or pos > 255:
    r = g = b = 0
  elif pos < 85:
    r = int(pos * 3)
    g = int(255 - pos * 3)
    b = 0
  elif pos < 170:
    pos -= 85
    r = int(255 - pos * 3)
    g = 0
    b = int(pos * 3)
  else:
    pos -= 170
    r = 0
    g = int(pos * 3)
    b = int(255 - pos * 3)
  return (r, g, b) if ORDER in (neopixel.RGB, neopixel.GRB) else (r, g, b, 0)

def rainbow_cycle(wait):
  for j in range(255):
    for i in range(num_pixels):
      pixel_index = (i * 256 // num_pixels) + j
      pixels[i] = wheel(pixel_index & 255)
    pixels.show()
    time.sleep(wait)

while True:
  rainbow_cycle(0.001)  # rainbow cycle with 1ms delay per step
$ sudo python3 rainbow.py

References