This is a LED matrix library that simplifies driving a LED matrix of any size created with WS2812B and WS2811 LED strips. It also is a virtual LED matrix simulator you can use to help create effects, and animations without the need for a physical matrix. When running effects you can execute them individually, or in a random playlist.
water_ripple_virtual.mp4
water_ripple_live.mp4
git clone git@github.com:natelewis/pi-led-matrix.git
cd pi-led-matrix
make bootstrap
make run rgb_test
# Red, blue, green... in a 600x300 window
# ctl-c to stop script
High level construction details of a LED matrix panel.
Shopping List:
- WS281x LED strips
- 5V power supply
- Raspberry Pi 4
- A few extra meters of 3 pin wire @ 22AWG
- Male/Female JST SM 3 Pin Connectors to create an extension cable from where your panel is to your Pi/PSU
- Curtain rod or other hangable rod you can attach your strips to
- Hobby wood/bamboo @ 3/8" wide to stick on the back of the LED strips to keep them straight
- A bit of patience -- Takes about 4-5 hours to put it all together
In this example I built a 60x30 array with 5V 300W 60A power supply, which is plenty of power for this size matrix.
-
Collect a 60 count of 30 LED per meter 1M strips
-
Build the matrix in a chain pattern:
_ _ _ _ ... | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |_| |_| |_|
-
Attach 5V power from the PSU to top of each strip in parallel ( every other one )
-
Connect GPIO 18 (pin 12) of the RPi4 to the green LED wire
-
Connect GND pin of the RPi4 to COM of the power supply
-
Hang the LED strips to the curtain rod or other mount with your adhesive of choice
-
Install RPi OS 32 bit
-
Get your Pi on your network, running headless and pull down this repo
-
Execute the following to globally install libraries and dependencies:
sudo apt update sudo apt install -y pkg-config sudo apt install -y ffmpeg libopenblas-dev libavformat-dev libavcodec-dev libswscale-dev git clone https://github.com/natelewis/pi-led-matrix.git cd pi-led-matrix make bootstrap cp default_config.json config.json
-
Update the
config.json
to adjust sizes or values if anything is different.
Running the test script will cycle between R..., G..., B... (repeat)...
Depending on what version of the strips you have, it might be possible the RGB colors are swapped around. You can fix this by changing the color_order
value in your config file.
make run effect=rgb_test
# ctl-c to stop script
LEDs will maintain their currently lit state when you cancel your script. You can use the off effect to turn them off:
make off
# alias to: make run effect=off
Custom effects are organized in the effects
directory with the following structure:
> src > effects > effect_name > effects.py
They can be displayed with:
make run effect=effect_name
Some that support options can be passed a config:
make run effect=effect_name config='{"some_json": "config settings"}'
View the effects list and usage details
Run a slide show of effects that run in random order with a delay between effects. When ever running a single effect, the playlist json will be display on execution, use this to build your custom playlist.
make playlist
You can choose what effects are in the playlist and the delay in the config.py
.
When emulating the LED array locally, it detects you do not have any of the adafruit modules installed and fails over to virtual mode. To synchronously pause your event loop when animating use the matrix.delay()
function. This will ensure your rendering window stays open while waiting.
If you want use this outside of the effects directory import the Matrix
class. If you are building inside an effect this is already been done for you and passed to your run()
function.
# import matrix if not in an effect run()
import sys
sys.path.append("./src")
from main import Matrix
matrix = Matrix()
# draw some random things to show how this works
matrix.reset() # black background (0, 0, 0)
matrix.line((0, 0), (60, 30), (255, 0, 0), 1) # diagonal red line
matrix.rectangle((5, 5), (55, 25), (0, 255, 0), 1) # green rectangle
matrix.circle((30, 15), 10, (0, 0, 255), 2) # blue circle
matrix.show()
matrix.delay(10000) # delay 10 seconds before shutting virtual window down
./.venv/python test.py
A simple effect:
def run(matrix, _):
"""flash rapidly between red and blue"""
while matrix.ready():
matrix.reset(matrix.color("red"))
matrix.show()
matrix.reset(matrix.color("blue"))
matrix.show()
matrix.circle((x,y), radius, (r, g, b), width)
Draw a circle from its center point with a given radius. A width of -1
will fill in the circle.
matrix.circle((30, 15), 10, (0, 0, 255), 3) # blue circle
matrix.show()
matrix.delay(5000)
matrix.color(css_color_name)
Return the color for any standard css color name.
matrix.reset(matrix.color('fuchsia')) # paint led's fuchsia (255, 0, 255)
matrix.show()
matrix.delay(5000)
matrix.delay(ms)
Sleep x amount of milliseconds.
matrix.delay(1000) # 1 second
matrix.delay(1000 * 60) # 1 minute
matrix.frame
Access to the numpy array that contains the matrix values. This can be manipulated, or tested against.
import numpy as np
def is_it_off:
# check if all values are 0's
return np.all(matrix.frame==0)
matrix.image(Image)
Display an image using the Python Imaging Library (PIL).
from PIL import Image
image = Image.open(image_file)
matrix.image(image)
matrix.show()
matrix.delay(5000)
matrix.line((x,y), (x,y), (r, g, b), width)
Draw a line from the start to the end coordinates.
matrix.line((0, 0), (60, 30), (255, 0, 0), 1) # diagonal red line
matrix.show()
matrix.delay(5000)
matrix.pixel((x,y), (r, g, b))
Draw a line from the start to the end coordinates.
matrix.line((30, 15), (255, 0, 0), 1) # diagonal red line
matrix.show()
matrix.delay(5000)
matrix.random_color()
Return a random color
matrix.line((0, 0), (60, 30), matrix.random_color(), 1) # random colored line
matrix.show()
matrix.delay(5000)
`matrix.rectangle((x,y), (x,y), (r, g, b), width)`
Draw a rectangle from the start to the end coordinates.
matrix.rectangle((5, 5), (55, 25), (255, 0, 0), 1) # red rectangle
matrix.show()
matrix.delay(5000)
matrix.reset((r, g, b))
Reset all the pixels on the matrix to the RGB value given. If no value is given it will default to all black (0, 0, 0).
matrix.reset((255, 0 , 0)) # all LEDs red
matrix.show()
matrix.delay(5000)
matrix.reset() # turn off all LEDs -- same as matrix.reset((0, 0, 0))
matrix.show()
matrix.show()
Paint the current image to the LEDs
matrix.reset((0, 0, 255))
matrix.show() # turn all LEDs blue
matrix.delay(1000)
matrix.reset()
matrix.show() # turn off all LEDs
matrix.sprite(sprite_map, start, color_map)
Draw a custom sprite of any size on the matrix, where the upper left corner is the starting coordinates.
# smiley face with a blue nose, green eyes and red smile in the upper hand corner of the matrix
matrix.sprite(
([ [' ', ' ', ' ', ' ', ' '],
['1', '1', ' ', '1', '1'],
['1', '1', ' ', '1', '1'],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', 'o', ' ', ' '],
[' ', ' ', 'o', ' ', ' '],
['x', ' ', ' ', ' ', 'x'],
[' ', 'x', 'x', 'x', ' '],
[' ', ' ', ' ', ' ', ' ']]),
(0, 0),
{
'1': (0, 255, 0), # 1's are green
'x': (255, 0, 0), # x's are read
'o': (0, 0, 255), # o's are blue
})
matrix.show()
matrix.delay(10000)
matrix.text(self, text, start, font_size, color, ttf_font_file)
Place the upper left point of the text at a given location. Custom font files should be placed in the ./fonts/
directory, and can be any ttf file. The default font is used if none is passed.
matrix.text('hello', (10,20), 16, (255,0,0))
matrix.show()
matrix.delay(5000)
matrix.text('hello', (10,20), 16, (255,0,0), 'custom.ttf')
matrix.show()
matrix.delay(5000)
Checkout CONTRIBUTING.md
Created by @natelewis. Released under the MIT license.