A Python library to drive MAX7219 LED matrices, WS2812 NeoPixels, and APA102 DotStar LEDs on Raspberry Pi
—
APA102/DotStar LED driver supporting SPI and bitbang interfaces with individual brightness control via alpha channel. APA102 LEDs offer higher refresh rates and more precise color control compared to WS281x chips.
Creates an APA102 device instance with configurable dimensions, interface selection, and pixel mapping.
class apa102:
def __init__(
self,
serial_interface=None,
width=8,
height=1,
cascaded=None,
rotate=0,
mapping=None
):
"""
Initialize APA102 DotStar LED device.
Parameters:
- serial_interface: Serial interface (SPI or bitbang), optional (defaults to bitbang)
- width: Number of pixels horizontally (default: 8)
- height: Number of pixels vertically (default: 1)
- cascaded: Total number of pixels in strip (overrides width/height if specified)
- rotate: Rotation angle (0, 1, 2, 3 for 0°, 90°, 180°, 270°)
- mapping: Array of pixel-to-physical offset mappings for non-standard layouts
"""Controls the RGB LED output with support for individual pixel brightness control through the alpha channel.
def display(self, image):
"""
Display a 32-bit RGBA PIL image on the APA102 LEDs.
The alpha channel controls individual pixel brightness.
Parameters:
- image: PIL Image object in mode 'RGBA' (32-bit color with alpha)
Alpha values: 0 = off, 255 = full brightness
RGB values: Standard 0-255 color channels
"""
def contrast(self, value):
"""
Set global LED intensity/brightness multiplier.
Parameters:
- value: Global brightness level (0-255)
Applied as multiplier to individual pixel alpha values
"""
def show(self):
"""
Not supported operation (no-op).
APA102 LEDs update immediately on display() calls.
"""
def hide(self):
"""
Not supported operation (no-op).
Use contrast(0) or display black image to turn off LEDs.
"""from luma.led_matrix.device import apa102
from luma.core.render import canvas
from PIL import Image
# Create 30-pixel APA102 strip with default bitbang interface
device = apa102(cascaded=30)
# Create RGBA image for brightness control
img = Image.new('RGBA', (30, 1))
pixels = img.load()
# Set colors with individual brightness
pixels[0, 0] = (255, 0, 0, 255) # Red at full brightness
pixels[1, 0] = (0, 255, 0, 128) # Green at 50% brightness
pixels[2, 0] = (0, 0, 255, 64) # Blue at 25% brightness
device.display(img)from luma.core.interface.serial import spi, noop
from luma.led_matrix.device import apa102
from luma.core.render import canvas
# Create SPI interface for faster communication
serial = spi(port=0, device=0, gpio=noop())
device = apa102(serial_interface=serial, cascaded=50)
# Draw with canvas (auto-converts to RGBA)
with canvas(device) as draw:
# Canvas drawing automatically sets full alpha
draw.point((0, 0), fill="red")
draw.point((1, 0), fill="green")
draw.point((2, 0), fill="blue")from luma.led_matrix.device import apa102
from PIL import Image
import numpy as np
# Create 8x8 LED matrix
device = apa102(width=8, height=8)
# Create gradient brightness pattern
img = Image.new('RGBA', (8, 8))
pixels = img.load()
for x in range(8):
for y in range(8):
# Distance-based brightness
distance = ((x - 3.5) ** 2 + (y - 3.5) ** 2) ** 0.5
brightness = max(0, int(255 - distance * 30))
pixels[x, y] = (255, 255, 255, brightness) # White with varying brightness
device.display(img)import time
import math
from luma.led_matrix.device import apa102
from PIL import Image
device = apa102(width=16, height=1)
# Breathing effect with individual pixel brightness
for step in range(100):
img = Image.new('RGBA', (16, 1))
pixels = img.load()
for i in range(16):
# Sine wave brightness pattern
brightness = int(128 + 127 * math.sin(step * 0.2 + i * 0.5))
hue = (i + step * 0.1) % 1.0
# Convert HSV to RGB
import colorsys
rgb = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
color = tuple(int(c * 255) for c in rgb)
pixels[i, 0] = (*color, brightness)
device.display(img)
time.sleep(0.05)from luma.led_matrix.device import apa102
from luma.core.render import canvas
device = apa102(cascaded=20)
# Set global brightness to 25%
device.contrast(64)
# Draw normally - global brightness will be applied
with canvas(device) as draw:
for i in range(20):
draw.point((i, 0), fill="white")
# Fade out gradually
for brightness in range(64, -1, -2):
device.contrast(brightness)
time.sleep(0.1)The device may raise the following exceptions:
luma.core.error.DeviceDisplayModeError: Invalid display dimensions or unsupported image modeAssertionError: Invalid parameter values (brightness out of range, invalid dimensions)RuntimeError: SPI interface initialization failures or communication errorsOverflowError: Too many pixels specified for available memory limitsAPA102 LEDs support 5-bit brightness control (32 levels) per pixel through the alpha channel:
The library automatically handles the conversion from 8-bit alpha values to 5-bit hardware brightness levels.
Install with Tessl CLI
npx tessl i tessl/pypi-luma--led-matrix