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]))