neopixel
WS2812 "NeoPixel" boards are addressable RGB LEDs: each one has a tiny chip that takes its colour off a single data wire, then passes the rest of the stream on. The shop sells an 8-LED stick and a 12-LED ring, and they chain together (DOUT to the next board's DIN). PyRasp provides Adafruit's CircuitPython neopixel driver.
The usual wiring is 5 V, ground and data on GPIO18:
from wiring import *
pi = Pi()
stick = NeoPixelStick()
pi.V5 >> stick.v5
stick.gnd >> pi.GND
pi.GPIO18 >> stick.dinSet pixels as tuples and call show():
import board
import neopixel
from time import sleep
pixels = neopixel.NeoPixel(board.D18, 8, brightness=0.5, auto_write=False)
while True:
for i in range(len(pixels)):
pixels[i] = (255, 0, 0)
pixels.show()
sleep(0.2)
pixels.fill((0, 0, 0))
pixels.show()
sleep(0.5)Plain GPIO numbers work too: neopixel.NeoPixel(18, 8).
Colours, slices and brightness
pixels[0] = (255, 0, 0) # red
pixels[0:4] = [(0, 0, 255)] * 4 # slice assignment: one colour per pixel
pixels.fill((0, 0, 0)) # everything off
pixels[0] = 0xFF0000 # packed int also accepted
pixels.brightness = 0.2 # 0 … 1, applies at show()
pixels.show()
Creating the strip with auto_write=True (the default) makes every assignment call show() immediately; turn it off when animating so the whole frame updates at once.
len(pixels) is the LED count and reading pixels[i] gives the stored (r, g, b) tuple. pixel_order defaults to neopixel.GRB, which is what WS2812 chips expect.
The rpi_ws281x alternative
The older C-library binding is provided as well, for code written against it:
from rpi_ws281x import PixelStrip, Color
strip = PixelStrip(8, 18, brightness=128) # num, GPIO, 0–255
strip.begin()
strip.setPixelColor(0, Color(255, 0, 0)) # packed red
strip.setPixelColorRGB(1, 0, 255, 0) # r, g, b
strip.show()
Color(r, g, b) packs the channels as the library does; Adafruit_NeoPixel is an alias of PixelStrip.
Going deeper
A chain works without extra code: bytes left over after one board consumes its share travel out of DOUT and into the next board's DIN. Put a stick and a ring on the same data pin and address both from one NeoPixel object — the stick's 8 LEDs are pixels 0–7, the ring's are the rest.
The whole strip is one framebuffer: nothing changes on the board until show() (or an auto_write assignment). That matches the hardware, where the stream is latched only when you stop sending.
For a non-addressable option with three PWM channels, see the RGB LED page and the RGB module kit; the NeoPixel level meter recipe combines a stick with an MCP3008.
Simulator vs real hardware
- Colours are bytes on the wire. The simulator sends the strip's bytes in
pixel_order; the WS2812 part takes its LEDs' share and passes the rest along the chain, exactly as the chips do. Sending RGB when the chip expects GRB swaps red and green, just like on a real stick. - Data rate and reset timing are not modelled. There is no 800 kHz signal and no 50 µs reset pulse;
show()is an instant transaction. Real strips can glitch with interrupts enabled or wrong timing — that cannot happen here. - Any GPIO works, if wired. Real
neopixel/rpi_ws281xneed GPIO18 (PWM), GPIO10 (SPI) or GPIO12/21, and rpi_ws281x needs root; the simulator only checks that the data pin's net reaches the part's DIN, so a data wire on any GPIO lights the LEDs. - Power is modelled. Each LED draws up to 60 mA at full white (plus ~1 mA idle). Chaining the 8-LED stick and the 12-LED ring and lighting everything white passes 1 A, and the simulator raises a "feed them from a separate 5 V supply" warning, as a real build would need. A strip wired to the 3.3 V rail instead of 5 V is below its 3.5 V minimum, so it counts as unpowered and simply never lights — no warning, just darkness.
- RGBW is not supported.
bpp=4andRGBW/GRBWconstants exist, but onlyr,g,bare stored and sent; there is no white channel or white chip in the shop. - rpi_ws281x's configuration is ignored.
freq_hz,dma,invert,channelandgammaare accepted but do nothing; brightness 0–255 scales the output, as the C library does.