class NeoPixelStrip: """SK6812 RGBW driver using built-in neopixel module.""" def __init__(self, pin_num, led_count): import neopixel from machine import Pin self.np = neopixel.NeoPixel(Pin(pin_num), led_count, bpp=4, timing=1) self.led_count = led_count def write_rgb(self, pixels): """Write list of (R,G,B) tuples. W channel set to 0.""" for i, (r, g, b) in enumerate(pixels): if i >= self.led_count: break self.np[i] = (r, g, b, 0) self.np.write() def write_rgbw(self, pixels): """Write list of (R,G,B,W) tuples.""" for i, (r, g, b, w) in enumerate(pixels): if i >= self.led_count: break self.np[i] = (r, g, b, w) self.np.write() def fill(self, r, g, b, w=0): """Fill all pixels with one color.""" self.np.fill((r, g, b, w)) self.np.write() def clear(self): self.fill(0, 0, 0, 0) class WS2801Strip: """WS2801 RGB driver using SPI — no external library needed.""" def __init__(self, spi_id, clk_pin, dat_pin, led_count): from machine import SPI, Pin self.spi = SPI(spi_id, baudrate=1000000, polarity=0, phase=0, sck=Pin(clk_pin), mosi=Pin(dat_pin)) self.led_count = led_count self._buf = bytearray(led_count * 3) def write_rgb(self, pixels): """Write list of (R,G,B) tuples.""" for i, (r, g, b) in enumerate(pixels): if i >= self.led_count: break off = i * 3 self._buf[off] = r self._buf[off + 1] = g self._buf[off + 2] = b self.spi.write(self._buf) def write_rgbw(self, pixels): """Write RGBW tuples — W channel is discarded (WS2801 is RGB only).""" for i, (r, g, b, _w) in enumerate(pixels): if i >= self.led_count: break off = i * 3 self._buf[off] = r self._buf[off + 1] = g self._buf[off + 2] = b self.spi.write(self._buf) def fill(self, r, g, b, w=0): for i in range(self.led_count): off = i * 3 self._buf[off] = r self._buf[off + 1] = g self._buf[off + 2] = b self.spi.write(self._buf) def clear(self): self.fill(0, 0, 0) def create_strip(config): """Factory: create the right strip driver from config dict.""" if config['strip_type'] == 'sk6812': return NeoPixelStrip(config['led_pin'], config['led_count']) elif config['strip_type'] == 'ws2801': return WS2801Strip(config['spi_id'], config.get('spi_clk_pin', 18), config.get('spi_dat_pin', 23), config['led_count']) else: raise ValueError('Unknown strip_type: ' + config['strip_type'])