A Python library to drive MAX7219 LED matrices, WS2812 NeoPixels, and APA102 DotStar LEDs on Raspberry Pi
—
Specialized driver for Pimoroni's Unicorn HAT HD, a 16x16 RGB LED matrix (256 LEDs total) that connects via SPI interface. This device provides high-resolution RGB display capabilities for Raspberry Pi projects.
Creates a Unicorn HAT HD device instance with configurable rotation.
class unicornhathd:
def __init__(
self,
serial_interface=None,
rotate=0,
**kwargs
):
"""
Initialize Unicorn HAT HD device.
Parameters:
- serial_interface: Serial SPI interface object (optional, defaults to None)
- rotate: Rotation angle (0, 1, 2, 3 for 0°, 90°, 180°, 270°)
- **kwargs: Additional parameters passed to parent device class
"""Controls the RGB LED matrix output with brightness and power management features.
def display(self, image):
"""
Display a 32-bit RGBA PIL image on the 16x16 LED matrix.
Alpha channel controls individual pixel brightness.
Parameters:
- image: PIL Image object in mode 'RGBA' (32-bit color with alpha)
Must be 16x16 pixels to match hardware dimensions
"""
def contrast(self, value):
"""
Set LED intensity/brightness for all pixels.
Parameters:
- value: Brightness level (0-255, where 0 is off and 255 is full brightness)
"""
def show(self):
"""
Restore contrast to previous level.
Brings LEDs back to normal brightness after hide().
"""
def hide(self):
"""
Set contrast to zero (all LEDs appear off).
LEDs are turned off but device remains active for quick restore.
"""from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
# Create SPI interface
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Draw simple pattern
with canvas(device) as draw:
draw.rectangle((0, 0, 15, 15), outline="white")
draw.point((8, 8), fill="red")import colorsys
from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Create rainbow gradient
with canvas(device) as draw:
for x in range(16):
for y in range(16):
# Calculate hue based on position
hue = (x + y) / 32.0
rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
color = tuple(int(c * 255) for c in rgb)
draw.point((x, y), fill=color)import time
import math
from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Plasma animation
for step in range(1000):
with canvas(device) as draw:
for x in range(16):
for y in range(16):
# Plasma calculation
v = math.sin((x + step) * 0.2) * 0.5
v += math.sin((y + step) * 0.15) * 0.5
v += math.sin((x + y + step) * 0.1) * 0.5
v += math.sin(math.sqrt((x - 8) ** 2 + (y - 8) ** 2) + step * 0.3) * 0.5
# Convert to color
hue = (v + 4) / 8.0
import colorsys
rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
color = tuple(int(c * 255) for c in rgb)
draw.point((x, y), fill=color)
time.sleep(0.05)from PIL import Image
from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Load and resize image to 16x16
image = Image.open("photo.jpg")
image = image.resize((16, 16), Image.LANCZOS)
image = image.convert("RGBA")
# Display with varying brightness
for brightness in range(0, 256, 5):
device.contrast(brightness)
device.display(image)
time.sleep(0.1)from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
# Create device rotated 90 degrees
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial, rotate=1)
# Draw text that will appear rotated
with canvas(device) as draw:
draw.text((2, 5), "HI", fill="green")import time
from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
from luma.core.virtual import viewport
from luma.core.legacy import text
from luma.core.legacy.font import proportional, CP437_FONT
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Create scrolling text
virtual = viewport(device, width=200, height=16)
text(virtual, (0, 0), "Scrolling message on Unicorn HAT HD!",
fill="white", font=proportional(CP437_FONT))
# Scroll the text
for offset in range(200 - 16):
virtual.set_position((offset, 0))
time.sleep(0.1)import time
from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import unicornhathd
from luma.core.render import canvas
serial = spi(port=0, device=0, gpio=noop())
device = unicornhathd(serial_interface=serial)
# Draw pattern
with canvas(device) as draw:
draw.ellipse((4, 4, 12, 12), fill="blue")
# Flash on and off
for _ in range(10):
device.hide() # Turn off
time.sleep(0.5)
device.show() # Turn on
time.sleep(0.5)The device may raise the following exceptions:
luma.core.error.DeviceDisplayModeError: Invalid image dimensions (must be 16×16) or unsupported modeRuntimeError: SPI interface initialization failures or communication errorsAssertionError: Invalid parameter values (brightness out of range, invalid rotation)OSError: Hardware access issues or permissions problemsInstall with Tessl CLI
npx tessl i tessl/pypi-luma--led-matrix