A CircuitPython library for managing segments of NeoPixel strips as independent addressable units (works on CircuitPython and Raspberry Pi)
Project description
CircuitPython Serial NeoPixel
A CircuitPython library that provides a SerialNeoPixel class for managing segments of NeoPixel LED strips as independent addressable units.
Overview
SerialNeoPixel acts as a wrapper around the standard Adafruit CircuitPython NeoPixel library, allowing you to treat a contiguous subset of pixels in a strip as a separate, independently addressable unit. This is particularly useful for projects where you want to logically divide a single physical strip into multiple sections without manually managing global pixel indices.
Key Features
- Segment-based addressing: Create multiple segments on a single strip, each with its own 0-based indexing
- Full sequence protocol support: Supports indexing, slicing, negative indices, and
len() - Pythonic interface: Feels like working with a native NeoPixel object
- No copying overhead: Direct pass-through to parent strip (no pixel data duplication)
- Brightness control: Access parent strip's brightness property (affects entire strip)
Installation
From PyPI (when published)
pip install circuitpython-serial-neopixel
Manual Installation
Copy serial_neo.py to your CircuitPython device's lib folder or your project directory.
Requirements
For CircuitPython (microcontrollers)
- CircuitPython 7.0 or higher
adafruit-circuitpython-neopixellibrary
For Raspberry Pi (standard Python)
- Python 3.7 or higher
adafruit-circuitpython-neopixellibrary- SPI enabled (via
raspi-configor/boot/config.txt) - NeoPixel DIN connected to GPIO10 (physical pin 19)
Quick Start
CircuitPython Example
import board
import neopixel
from serial_neo import SerialNeoPixel
# Create a NeoPixel strip with 30 LEDs
strip = neopixel.NeoPixel(board.D18, 30, brightness=0.3, auto_write=False)
# Create three segments on the same strip
segment1 = SerialNeoPixel(strip, 0, 10) # Pixels 0-9
segment2 = SerialNeoPixel(strip, 10, 10) # Pixels 10-19
segment3 = SerialNeoPixel(strip, 20, 10) # Pixels 20-29
# Each segment has independent 0-based indexing
segment1[0] = (255, 0, 0) # Red - affects strip pixel 0
segment2[0] = (0, 255, 0) # Green - affects strip pixel 10
segment3[0] = (0, 0, 255) # Blue - affects strip pixel 20
# Update the physical strip
segment1.show() # Any segment can call show() (affects entire strip)
Raspberry Pi Example (Standard Python)
import board
import neopixel
from serial_neo import SerialNeoPixel
# Create a NeoPixel strip with 30 LEDs on GPIO10 (physical pin 19)
# Note: Requires SPI enabled and sudo-less access configured
strip = neopixel.NeoPixel(board.D10, 30, brightness=0.3, auto_write=False)
# Create segments exactly the same way as CircuitPython
segment1 = SerialNeoPixel(strip, 0, 10)
segment2 = SerialNeoPixel(strip, 10, 10)
segment3 = SerialNeoPixel(strip, 20, 10)
# Same API works on both platforms
segment1[0] = (255, 0, 0)
segment2[0] = (0, 255, 0)
segment3[0] = (0, 0, 255)
segment1.show()
Usage Examples
Basic Indexing
# Set individual pixels
segment[0] = (255, 0, 0) # First pixel
segment[5] = (0, 255, 0) # Sixth pixel
segment[-1] = (0, 0, 255) # Last pixel (negative indexing)
# Get pixel colors
color = segment[0] # Returns (R, G, B) or (R, G, B, W) tuple
last_color = segment[-1] # Get last pixel
Slice Operations
# Set multiple pixels at once
segment[0:3] = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] # First three pixels
# Set a range to the same color
segment[5:10] = [(128, 128, 128)] * 5 # Pixels 5-9 to gray
# Use slice with step
segment[::2] = [(255, 0, 0)] * 5 # Every other pixel to red
# Get multiple pixels
colors = segment[0:5] # Returns list of color tuples
Fill Operations
# Fill entire segment with one color
segment.fill((255, 0, 0)) # Fill with red
# Clear a segment
segment.fill((0, 0, 0)) # Turn off all pixels
Brightness Control
Important: The brightness property affects the entire parent strip, not just the individual segment.
# Get current brightness
current = segment.brightness # Returns float 0.0-1.0
# Set brightness (affects ALL segments on the same strip)
segment.brightness = 0.5 # 50% brightness for entire strip
# This also affects all other segments sharing the same parent strip
segment1.brightness = 0.3 # segment2 and segment3 are also affected
Working with Multiple Segments
import board
import neopixel
from serial_neo import SerialNeoPixel
# 60-pixel strip divided into 6 segments of 10 pixels each
strip = neopixel.NeoPixel(board.D18, 60, auto_write=False)
segments = [SerialNeoPixel(strip, i*10, 10) for i in range(6)]
# Animate each segment independently
for i, seg in enumerate(segments):
seg.fill(colors[i])
strip.show()
Advanced: Overlapping Segments
You can create overlapping segments if needed (though use carefully):
full_strip = SerialNeoPixel(strip, 0, 30) # All 30 pixels
left_half = SerialNeoPixel(strip, 0, 15) # First 15 pixels
right_half = SerialNeoPixel(strip, 15, 15) # Last 15 pixels
center = SerialNeoPixel(strip, 10, 10) # Middle 10 pixels (overlaps both halves)
API Reference
SerialNeoPixel(strip, pixel_start, pixel_count)
Create a new segment wrapper.
Parameters:
strip: Parent NeoPixel strip objectpixel_start: Starting index in parent strip (0-based)pixel_count: Number of pixels in this segment
Methods
fill(color)
Fill all pixels in the segment with the specified color.
Parameters:
color: RGB tuple(r, g, b)or RGBW tuple(r, g, b, w)with values 0-255
show()
Update the physical LED strip to display current pixel colors. Affects the entire parent strip.
Properties
brightness
Get or set the brightness of the parent strip (0.0 to 1.0).
Warning: This affects the entire parent strip, not just this segment. All segments sharing the same parent will be affected.
Sequence Protocol
The class implements Python's sequence protocol:
len(segment): Returns number of pixels in segmentsegment[i]: Get/set pixel at indexi(supports negative indices)segment[start:stop:step]: Get/set slice of pixelsrepr(segment): String representation showing start position and count
Platform Compatibility
This library works on both:
- CircuitPython microcontrollers: Circuit Playground Express, Raspberry Pi Pico, Metro M4, etc.
- Raspberry Pi with standard Python: Pi 3, Pi 4, Pi 5, Pi Zero W, etc.
The same code works on both platforms with only minor hardware pin differences (e.g., board.D18 vs board.D10).
Raspberry Pi Setup
To use NeoPixels on Raspberry Pi, you need to:
-
Enable SPI via
raspi-config:sudo raspi-config # Navigate to: Interfacing Options -> SPI -> Enable
-
Install the library:
pip3 install circuitpython-serial-neopixel
-
Connect your NeoPixel strip:
- DIN (Data In) → GPIO10 (physical pin 19)
- 5V → 5V power
- GND → Ground
-
Configure sudo-less access (optional, for running without sudo): See Adafruit's documentation for detailed setup.
Limitations and Caveats
-
Brightness is strip-wide: The
brightnessproperty affects the entire parent strip, not individual segments. If multiple segments share a parent strip, changing brightness on one affects all. -
No bounds checking between segments: You can create overlapping segments. The library doesn't prevent this, as it might be intentional for some use cases.
-
show()updates entire strip: Callingshow()on any segment updates the entire physical strip, not just that segment's pixels. -
Requires parent strip compatibility: The parent strip object must support the standard NeoPixel interface (
__getitem__,__setitem__,show(),brightness). -
Auto-write behavior inherited: If the parent strip has
auto_write=True, changes may appear immediately. For better performance with segments, useauto_write=Falseon the parent strip and callshow()manually.
Performance Tips
- Use
auto_write=False: Create the parent strip withauto_write=Falseand callshow()manually after batch updates:
strip = neopixel.NeoPixel(board.D18, 30, auto_write=False)
segment = SerialNeoPixel(strip, 0, 10)
# Make multiple changes
segment[0] = (255, 0, 0)
segment[1] = (0, 255, 0)
segment[2] = (0, 0, 255)
# Update once
segment.show()
-
Use
fill()for uniform colors: It's more efficient than setting pixels individually. -
Batch slice operations: Use slice assignment instead of loops when possible:
# Good
segment[0:5] = [(255, 0, 0)] * 5
# Less efficient
for i in range(5):
segment[i] = (255, 0, 0)
Examples
See the examples directory for more detailed usage examples (coming soon).
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Credits
Built on top of the Adafruit CircuitPython NeoPixel library.
Support
For bugs and feature requests, please open an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file circuitpython_serial_neopixel-1.0.0.tar.gz.
File metadata
- Download URL: circuitpython_serial_neopixel-1.0.0.tar.gz
- Upload date:
- Size: 7.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3ca7190b1ebce5aaf82575904c17d280eae2c36b7ef8709f2b7d5416ccf0447
|
|
| MD5 |
b5d990513d1c9fc9f5db2ea8d4c32b06
|
|
| BLAKE2b-256 |
8aa30a0c50f7d1c65a2b255c2963773a897c2ad393b73f099b2e2fd473c7777e
|
File details
Details for the file circuitpython_serial_neopixel-1.0.0-py3-none-any.whl.
File metadata
- Download URL: circuitpython_serial_neopixel-1.0.0-py3-none-any.whl
- Upload date:
- Size: 7.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5925ccd22021e771c979bc81f8f3610295e47429dd2688f37293b1b3e35e6644
|
|
| MD5 |
467c65adbeaf3545e54ef225518b249c
|
|
| BLAKE2b-256 |
fbafb11c9442c32f0555eade24e211d8c7f0eeb7456289495c1bdf92634e1b6d
|