A very simple threaded and thread-safe class to control a string of ws2812 LED strips using SPI interfaces on Raspberry Pi/Orange Pi/etc. single board computers (SBCs) running Linux.
- The
numpy
package to work around the limited capabilities of a low-CPU-power computer. Python is quite expensive to do maths in, as well as move data around but this package, along with the Python packagespidev
andnumpy
use the buffer protocol to massively improve this (https://docs.python.org/3/c-api/buffer.html).- Try to precompute the colors you need in memory in an
numpy.array(... , dtype=uint8)
and then use a loop to write them with a slicefoo[5:50]
as this prevents Python allocating memory for, and converting every single byte into auint8
, every time it updates the LED string. - If not using
numpy
arrays use simple Pythonlist
instead as this will be 1000x faster than iterating through adict
orset
. (Leverage Python buffer protocol usingnumpy.array
orlist
to transfer content by reference tospidev.writebytes2()
.
- Try to precompute the colors you need in memory in an
- An activated SPI port on your particular SBC using device overlays so the file
/dev/spidevX.Y
(typically/dev/spidev0.0
) appears on your SBC.- SPI on a Rasberry Pi: https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md.
- An example on Armbian (typically /boot/armbianEnv.txt) the OrangePi: https://unix.stackexchange.com/questions/496070/how-to-enable-spi-on-orange-pi-pc-in-armbian.
- User access to the SPI device node in
/dev
.- An example
udev
rule is provided,99-spidev.rules
, which can be copied into/etc/udev/rules.d
. (It will not take effect untiludev
is reloaded or your SBC rebooted.) - The example
udev
rule makes the/dev/spidevX.Y
nodes available to members of the groupspidev
- this may not be present on your system so you can create it withsudo addgroup spidev
. Remember to add the user to this new group withsudo adduser username spidev
.
- An example
Please note that an OrangePi Zero (32 bit ARM w. 512MB of RAM) can drive a string of >100 consistently with 1ms updates @5% CPU using a precomputed lookup table to generate the bytes sent out of the SPI bus. A normal SBC cannot power many LEDs - remember to use a separate high current DC supply if using 10+!). Start with just 3-4 if you are powering it from the SBC to test it out, when it is working you can increase the numbers to find out the limits of your particular SPI driver, CPU, RAM combination. If you do not use a separate supply you could possibly damage your SBC.
- Import as a library.
- Initialize an instance for each SPI port with WS2812 LEDs attached.
- use
.init
orinit_from_dict
SPIws2812.init( (bus: int, cs: int). num_leds:int )
e.g.SPIws2812( (1,0), 15) )
SPIws2812.init_from_dict(dict)
e.g.SPIws2812.init_from_dict({"spidev": Path("/dev/spidev0.0"), "num_leds": 15})
- Start threads and open port with
spi.start()
- Start animations with these functions:
spi.breathe()
spi.chase()
- ...
- Stop library, releasing spidev, & stopping threads:
spi.stop()
Simply install with pip from the repository with pip install https://...../ - it will install necessary pre-reqs.
This is already designed and built to be used as a library inside your own python code.
On an Ubuntu or Debian system:
sudo dash -c "apt update; apt dist-upgrade -y; apt install -y python3-pip python3-setuptools python3-dev python3-numpy"
git clone https://github.com/mattaw/ws2812-spi-python.git
cd ws2812-spi-python
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install -U pip setuptools pip-tools
pip-sync requirements.txt
If you wish to modify the code, or develop it further install the development packages with:
pip-sync dev-requirements.txt
Copyright 2021 Dr. Matthew Swabey Copyright 2021 Purdue University
License Apache 2.0, see the LICENSE file for full details.