diff --git a/pico/src/patterns/calibration.py b/pico/src/patterns/calibration.py index 2f2d874..c0d1e8e 100644 --- a/pico/src/patterns/calibration.py +++ b/pico/src/patterns/calibration.py @@ -1,6 +1,6 @@ """Calibration: strips 2 and 6 only. First 10 green, then alternating 10 blue / 10 red. 10% brightness.""" -BRIGHTNESS = 0.10 +BRIGHTNESS = 1 BLOCK = 10 STRIPS_ON = (2, 6) # 0-based: 3rd and 7th strip only @@ -22,6 +22,7 @@ class Calibration: green = _scale(GREEN, BRIGHTNESS) red = _scale(RED, BRIGHTNESS) blue = _scale(BLUE, BRIGHTNESS) + blue = (0,0,0) on_set = set(STRIPS_ON) for strip_idx, strip in enumerate(strips): n = strip.num_leds diff --git a/pico/src/patterns/chase.py b/pico/src/patterns/chase.py index 837ac21..ace1058 100644 --- a/pico/src/patterns/chase.py +++ b/pico/src/patterns/chase.py @@ -35,7 +35,7 @@ class Chase: segment_length = n1 + n2 # Calculate position from step_count - step_count = self.driver.step + step_count = int(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 @@ -52,23 +52,23 @@ class Chase: # 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): + # Draw repeating pattern starting at position across all physical strips + num_leds = self.driver.num_leds + num_strips = len(self.driver.strips) + for i in range(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 + color = color0 if relative_pos < n1 else color1 - self.driver.n.write() + # Apply this logical LED to every physical strip via driver.set() + for strip_idx in range(num_strips): + self.driver.set(strip_idx, i, color) + + self.driver.show_all() # Increment step for next beat self.driver.step = step_count + 1 @@ -97,23 +97,23 @@ class Chase: 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): + # Draw repeating pattern starting at position across all physical strips + num_leds = self.driver.num_leds + num_strips = len(self.driver.strips) + for i in range(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 + color = color0 if relative_pos < n1 else color1 - self.driver.n.write() + # Apply this logical LED to every physical strip via driver.set() + for strip_idx in range(num_strips): + self.driver.set(strip_idx, i, color) + + self.driver.show_all() # Increment step step_count += 1 diff --git a/pico/src/patterns/spin.py b/pico/src/patterns/spin.py index f3b9f87..a244c75 100644 --- a/pico/src/patterns/spin.py +++ b/pico/src/patterns/spin.py @@ -2,7 +2,7 @@ import utime -SPAN = 10 # LEDs on each side of center (match Grab) +SPAN = 0 # LEDs on each side of center (match Grab) LUT_SIZE = 256 # gradient lookup table entries @@ -12,6 +12,9 @@ class Spin: def run(self, preset): strips = self.driver.strips + + self.driver.fill((0, 0, 0)) + self.driver.show_all() active_indices = (0, 4) c0 = preset.c[0] c1 = preset.c[1] @@ -58,8 +61,8 @@ class Spin: n = strip.num_leds mid = midpoints[idx] - # Expand arms: inside (strip 1, idx 0) moves slower, outside (strip 5, idx 4) faster - step = max(1, rate // 2) if idx == 0 else rate + # Expand arms at the same rate on both sides + step = max(1, rate) new_left = max(margin, left[idx] - step) new_right = min(n - margin, right[idx] + step) diff --git a/pico/test/test_spin.py b/pico/test/test_spin.py new file mode 100644 index 0000000..4b36e17 --- /dev/null +++ b/pico/test/test_spin.py @@ -0,0 +1,128 @@ +""" +On-device test for the Spin pattern using mpremote and Presets. + +Usage (from pico/ dir or project root with adjusted paths): + + mpremote connect cp src/*.py : + mpremote connect cp src/patterns/*.py :patterns + mpremote connect cp lib/*.py : + mpremote connect cp presets.json : + mpremote connect cp test/test_spin.py : + mpremote connect run test_spin.py + +This script: + - Instantiates Presets + - Creates a few in-memory spin presets with different parameters + - Runs each one for a short time so you can visually compare behaviour +""" + +import utime +from presets import Presets, Preset + + +def make_spin_preset( + name, + color_inner, + color_outer, + rate=4, + delay_ms=30, + margin=0, + brightness=255, +): + """Helper to build a Preset dict for the spin pattern.""" + data = { + "p": "spin", + "c": [color_inner, color_outer], + "b": brightness, + "d": delay_ms, + "n1": rate, # expansion step per tick + "n2": margin, # margin from strip ends + "a": True, + } + return name, Preset(data) + + +def run_preset(presets, name, preset_obj, duration_ms): + """Run a given spin preset for duration_ms using the existing tick loop.""" + # Start each preset from a blank frame so both sides are balanced. + presets.select("off") + presets.tick() + + presets.presets[name] = preset_obj + presets.select(name) + + start = utime.ticks_ms() + while utime.ticks_diff(utime.ticks_ms(), start) < duration_ms: + presets.tick() + utime.sleep_ms(10) + + +def main(): + presets = Presets() + presets.load() + + # Ensure we start from a blank frame. + presets.select("off") + presets.tick() + + print("Starting spin pattern test...") + + # Use strip 0 length to derive a reasonable margin. + ref_len = presets.strip_length(0) + margin_small = ref_len // 16 if ref_len > 0 else 0 + margin_large = ref_len // 8 if ref_len > 0 else 0 + + spin_presets = [] + + # 1. Slow spin, warm white to orange, small margin + spin_presets.append( + make_spin_preset( + "spin_slow_warm", + color_inner=(255, 200, 120), + color_outer=(255, 100, 0), + rate=2, + delay_ms=40, + margin=margin_small, + brightness=255, + ) + ) + + # 2. Medium spin, cyan to magenta, larger margin + spin_presets.append( + make_spin_preset( + "spin_medium_cyan_magenta", + color_inner=(0, 255, 180), + color_outer=(255, 0, 180), + rate=4, + delay_ms=30, + margin=margin_large, + brightness=255, + ) + ) + + # 3. Fast spin, white to off (fade outwards), no margin + spin_presets.append( + make_spin_preset( + "spin_fast_white", + color_inner=(255, 255, 255), + color_outer=(0, 0, 0), + rate=6, + delay_ms=20, + margin=0, + brightness=255, + ) + ) + + # Run each spin preset for about 6 seconds + for name, preset_obj in spin_presets: + print("Running spin preset:", name) + run_preset(presets, name, preset_obj, duration_ms=6000) + + print("Spin pattern test finished. Turning off LEDs.") + presets.select("off") + presets.tick() + + +if __name__ == "__main__": + main() +