test: WS client sends nested {name:{...}}; add iterations and repeat-delay; include n per message; use n1/n2 for alternating
70 lines
2.8 KiB
Python
70 lines
2.8 KiB
Python
from machine import Pin
|
|
from neopixel import NeoPixel
|
|
import utime
|
|
|
|
|
|
class PatternBase:
|
|
def __init__(self, pin, num_leds, color1=(0,0,0), color2=(0,0,0), brightness=127, selected="rainbow_cycle", delay=100):
|
|
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
|
|
self.num_leds = num_leds
|
|
self.pattern_step = 0
|
|
self.last_update = utime.ticks_ms()
|
|
self.delay = delay
|
|
self.brightness = brightness
|
|
self.patterns = {}
|
|
self.selected = selected
|
|
self.run = True
|
|
# Ensure colors list always starts with at least two for robust transition handling
|
|
self.colors = [color1, color2] if color1 != color2 else [color1, (255, 255, 255)] # Fallback if initial colors are same
|
|
if not self.colors: # Ensure at least one color exists
|
|
self.colors = [(0, 0, 0)]
|
|
|
|
self.transition_duration = delay * 50 # Default transition duration
|
|
self.hold_duration = delay * 10 # Default hold duration at each color
|
|
self.transition_step = 0 # Current step in the transition
|
|
self.current_color_idx = 0 # Index of the color currently being held/transitioned from
|
|
self.current_color = self.colors[self.current_color_idx] # The actual blended color
|
|
|
|
self.hold_start_time = utime.ticks_ms() # Time when the current color hold started
|
|
|
|
# New attributes for scanner patterns (moved from Patterns to PatternBase as they are generic enough)
|
|
self.scanner_direction = 1 # 1 for forward, -1 for backward
|
|
self.scanner_tail_length = 3 # Number of trailing pixels
|
|
|
|
# Store last pattern-returned delay to use for subsequent gating
|
|
self._last_returned_delay = None
|
|
def update_num_leds(self, pin, num_leds):
|
|
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
|
|
self.num_leds = num_leds
|
|
|
|
def set_color(self, num, color):
|
|
if 0 <= num < len(self.colors):
|
|
self.colors[num] = color
|
|
elif num == len(self.colors): # Allow setting a new color at the end
|
|
self.colors.append(color)
|
|
return True
|
|
return False
|
|
|
|
def del_color(self, num):
|
|
if 0 <= num < len(self.colors):
|
|
del self.colors[num]
|
|
return True
|
|
return False
|
|
|
|
def apply_brightness(self, color, brightness_override=None):
|
|
effective_brightness = brightness_override if brightness_override is not None else self.brightness
|
|
return tuple(int(c * effective_brightness / 255) for c in color)
|
|
|
|
def write(self):
|
|
self.n.write()
|
|
|
|
def fill(self, color=None):
|
|
fill_color = color if color is not None else self.colors[0]
|
|
self.n.fill(fill_color)
|
|
self.n.write()
|
|
|
|
def off(self):
|
|
self.fill((0, 0, 0))
|
|
|
|
def on(self):
|
|
self.fill(self.apply_brightness(self.colors[0])) |