import utime class Chase: def __init__(self, driver): self.driver = driver def run(self, preset): """Chase pattern: n1 LEDs of color0, n2 LEDs of color1, repeating. Moves by n3 on even steps, n4 on odd steps (n3/n4 can be positive or negative)""" colors = preset.c if len(colors) < 1: # Need at least 1 color return # Access colors, delay, and n values from preset if not colors: return # If only one color provided, use it for both colors if len(colors) < 2: color0 = colors[0] color1 = colors[0] else: color0 = colors[0] color1 = colors[1] color0 = self.driver.apply_brightness(color0, preset.b) color1 = self.driver.apply_brightness(color1, preset.b) n1 = max(1, int(preset.n1)) # LEDs of color 0 n2 = max(1, int(preset.n2)) # LEDs of color 1 n3 = int(preset.n3) # Step movement on even steps (can be negative) n4 = int(preset.n4) # Step movement on odd steps (can be negative) segment_length = n1 + n2 # Calculate position from step_count step_count = self.driver.step # Position alternates: step 0 adds n3, step 1 adds n4, step 2 adds n3, etc. if step_count % 2 == 0: # Even steps: (step_count//2) pairs of (n3+n4) plus one extra n3 position = (step_count // 2) * (n3 + n4) + n3 else: # Odd steps: ((step_count+1)//2) pairs of (n3+n4) position = ((step_count + 1) // 2) * (n3 + n4) # Wrap position to keep it reasonable max_pos = self.driver.num_leds + segment_length position = position % max_pos if position < 0: position += max_pos # If auto is False, run a single step and then stop if not preset.a: # Clear all LEDs self.driver.n.fill((0, 0, 0)) # Draw repeating pattern starting at position for i in range(self.driver.num_leds): # Calculate position in the repeating segment relative_pos = (i - position) % segment_length if relative_pos < 0: relative_pos = (relative_pos + segment_length) % segment_length # Determine which color based on position in segment if relative_pos < n1: self.driver.n[i] = color0 else: self.driver.n[i] = color1 self.driver.n.write() # Increment step for next beat self.driver.step = step_count + 1 # Allow tick() to advance the generator once yield return # Auto mode: continuous loop # Use transition_duration for timing and force the first update to happen immediately transition_duration = max(10, int(preset.d)) last_update = utime.ticks_ms() - transition_duration while True: current_time = utime.ticks_ms() if utime.ticks_diff(current_time, last_update) >= transition_duration: # Calculate current position from step_count if step_count % 2 == 0: position = (step_count // 2) * (n3 + n4) + n3 else: position = ((step_count + 1) // 2) * (n3 + n4) # Wrap position max_pos = self.driver.num_leds + segment_length position = position % max_pos if position < 0: position += max_pos # Clear all LEDs self.driver.n.fill((0, 0, 0)) # Draw repeating pattern starting at position for i in range(self.driver.num_leds): # Calculate position in the repeating segment relative_pos = (i - position) % segment_length if relative_pos < 0: relative_pos = (relative_pos + segment_length) % segment_length # Determine which color based on position in segment if relative_pos < n1: self.driver.n[i] = color0 else: self.driver.n[i] = color1 self.driver.n.write() # Increment step step_count += 1 self.driver.step = step_count last_update = current_time # Yield once per tick so other logic can run yield