patterns: centralize timing in tick(); remove selected-delay coupling; update self-test to use per-config durations

This commit is contained in:
2025-09-15 12:56:57 +12:00
parent 44cb35d1aa
commit 80d5a66fab
2 changed files with 326 additions and 286 deletions

View File

@@ -13,6 +13,7 @@ class PatternBase:
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
@@ -26,10 +27,12 @@ class PatternBase:
self.hold_start_time = utime.ticks_ms() # Time when the current color hold started
# New attributes for scanner patterns
# 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
# Removed: selected_delay caching
def sync(self):
self.pattern_step=0
self.last_update = utime.ticks_ms() - self.delay
@@ -40,14 +43,32 @@ class PatternBase:
self.hold_start_time = utime.ticks_ms() # Reset hold time
# Reset scanner specific variables
self.scanner_direction = 1
self.tick()
# self.tick() # Tick moved to Patterns, as patterns dict is there
def set_pattern_step(self, step):
self.pattern_step = step
def tick(self):
if self.patterns[self.selected]:
if self.patterns.get(self.selected) and self.run:
# Compute gating interval per pattern based on current delay
interval = None
if self.selected in ("color_wipe", "theater_chase", "blink", "scanner", "fill_range", "n_chase", "alternating"):
interval = self.delay
elif self.selected == "rainbow_cycle":
interval = max(1, int(self.delay // 5))
elif self.selected == "flicker":
interval = max(1, int(self.delay // 5))
elif self.selected == "bidirectional_scanner":
interval = max(1, int(self.delay // 100))
# Patterns intentionally not gated here: off, on, external, pulse, color_transition
if interval is not None:
current_time = utime.ticks_ms()
if utime.ticks_diff(current_time, self.last_update) < interval:
return interval
self.patterns[self.selected]()
return interval
return None
def update_num_leds(self, pin, num_leds):
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
@@ -59,6 +80,7 @@ class PatternBase:
# Update transition duration and hold duration when delay changes
self.transition_duration = self.delay * 50
self.hold_duration = self.delay * 10
# No cached interval
def set_brightness(self, brightness):
@@ -157,6 +179,7 @@ class PatternBase:
return tuple(int(c * effective_brightness / 255) for c in color)
def select(self, pattern):
# Removed self.run = True here. It should be handled by Patterns class.
if pattern in self.patterns:
self.selected = pattern
self.sync() # Reset pattern state when selecting a new pattern