diff --git a/README.md b/README.md index c5e7961..77ff7a4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ MicroPython-based LED driver application for ESP32 microcontrollers. led-driver/ ├── src/ │ ├── main.py # Main application code -│ ├── patterns.py # LED pattern implementations (includes Preset and Patterns classes) +│ ├── presets.py # LED pattern implementations (includes Preset and Presets classes) │ ├── settings.py # Settings management │ └── p2p.py # Peer-to-peer communication ├── test/ # Pattern tests diff --git a/src/main.py b/src/main.py index 134e9ae..adcec2d 100644 --- a/src/main.py +++ b/src/main.py @@ -2,14 +2,14 @@ from settings import Settings from machine import WDT from espnow import ESPNow import network -from patterns import Patterns +from presets import Presets from utils import convert_and_reorder_colors import json settings = Settings() print(settings) -patterns = Patterns(settings["led_pin"], settings["num_leds"]) +presets = Presets(settings["led_pin"], settings["num_leds"]) wdt = WDT(timeout=10000) wdt.feed() @@ -24,7 +24,7 @@ e.active(True) while True: wdt.feed() - patterns.tick() + presets.tick() if e.any(): host, msg = e.recv() data = json.loads(msg) @@ -35,7 +35,7 @@ while True: # Global brightness (0–255) for this device if "b" in data: try: - patterns.b = max(0, min(255, int(data["b"]))) + presets.b = max(0, min(255, int(data["b"]))) except (TypeError, ValueError): pass if "presets" in data: @@ -43,11 +43,11 @@ while True: # Convert hex color strings to RGB tuples and reorder based on device color order if "c" in preset_data: preset_data["c"] = convert_and_reorder_colors(preset_data["c"], settings) - patterns.edit(name, preset_data) + presets.edit(name, preset_data) if settings.get("name") in data.get("select", {}): select_list = data["select"][settings.get("name")] # Select value is always a list: ["preset_name"] or ["preset_name", step] if select_list: preset_name = select_list[0] step = select_list[1] if len(select_list) > 1 else None - patterns.select(preset_name, step=step) + presets.select(preset_name, step=step) diff --git a/src/preset.py b/src/preset.py new file mode 100644 index 0000000..603e5d2 --- /dev/null +++ b/src/preset.py @@ -0,0 +1,24 @@ +class Preset: + def __init__(self, data): + # Set default values for all preset attributes + self.p = "off" + self.d = 100 + self.b = 127 + self.c = [(255, 255, 255)] + self.a = True + self.n1 = 0 + self.n2 = 0 + self.n3 = 0 + self.n4 = 0 + self.n5 = 0 + self.n6 = 0 + + # Override defaults with provided data + self.edit(data) + + def edit(self, data=None): + if not data: + return False + for key, value in data.items(): + setattr(self, key, value) + return True diff --git a/src/patterns.py b/src/presets.py similarity index 90% rename from src/patterns.py rename to src/presets.py index 0cbc1a2..6b46695 100644 --- a/src/patterns.py +++ b/src/presets.py @@ -1,6 +1,7 @@ from machine import Pin from neopixel import NeoPixel import utime +from preset import Preset # Short-key parameter mapping for convenience setters @@ -22,32 +23,7 @@ param_mapping = { "auto": "auto", } -class Preset: - def __init__(self, data): - # Set default values for all preset attributes - self.p = "off" - self.d = 100 - self.b = 127 - self.c = [(255, 255, 255)] - self.a = True - self.n1 = 0 - self.n2 = 0 - self.n3 = 0 - self.n4 = 0 - self.n5 = 0 - self.n6 = 0 - - # Override defaults with provided data - self.edit(data) - - def edit(self, data=None): - if not data: - return False - for key, value in data.items(): - setattr(self, key, value) - return True - -class Patterns: +class Presets: def __init__(self, pin, num_leds): self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds) self.num_leds = num_leds @@ -154,16 +130,26 @@ class Patterns: return (0, pos * 3, 255 - pos * 3) def blink(self, preset): + """Blink pattern: toggles LEDs on/off using preset delay, cycling through colors.""" + # Use provided colors, or default to white if none + colors = preset.c if preset.c else [(255, 255, 255)] + color_index = 0 state = True # True = on, False = off last_update = utime.ticks_ms() while True: current_time = utime.ticks_ms() - if utime.ticks_diff(current_time, last_update) >= preset.d: + # Re-read delay each loop so live updates to preset.d take effect + delay_ms = max(1, int(preset.d)) + if utime.ticks_diff(current_time, last_update) >= delay_ms: if state: - color = preset.c[0] if preset.c else (255, 255, 255) - self.fill(self.apply_brightness(color, preset.b)) + base_color = colors[color_index % len(colors)] + color = self.apply_brightness(base_color, preset.b) + self.fill(color) + # Advance to next color for the next "on" phase + color_index += 1 else: + # "Off" phase: turn all LEDs off self.fill((0, 0, 0)) state = not state last_update = current_time @@ -447,25 +433,41 @@ class Patterns: last_tail_move = utime.ticks_ms() phase = "growing" # "growing", "shrinking", or "off" - + + # Support up to two colors (like chase). If only one color is provided, + # use black for the second; if none, default to white. colors = preset.c - color = self.apply_brightness(colors[0] if colors else (255, 255, 255), preset.b) + if not colors: + base0 = base1 = (255, 255, 255) + elif len(colors) == 1: + base0 = colors[0] + base1 = (0, 0, 0) + else: + base0 = colors[0] + base1 = colors[1] + + color0 = self.apply_brightness(base0, preset.b) + color1 = self.apply_brightness(base1, preset.b) while True: current_time = utime.ticks_ms() - # Clear all LEDs - self.n.fill((0, 0, 0)) + # Background: use second color during the "off" phase, otherwise clear to black + if phase == "off": + self.n.fill(color1) + else: + self.n.fill((0, 0, 0)) # Calculate segment length segment_length = (head - tail) % self.num_leds if segment_length == 0 and head != tail: segment_length = self.num_leds - # Draw segment from tail to head + # Draw segment from tail to head as a solid color (no per-LED alternation) + current_color = color0 for i in range(segment_length + 1): led_pos = (tail + i) % self.num_leds - self.n[led_pos] = color + self.n[led_pos] = current_color # Move head continuously at n1 LEDs per second if utime.ticks_diff(current_time, last_head_move) >= head_delay: @@ -494,7 +496,7 @@ class Patterns: elif min_length > 0 and current_length <= min_length: phase = "growing" # Cycle repeats else: # phase == "off" - # Off phase: all LEDs off for 1 step, then restart + # Off phase: second color fills the ring for 1 step, then restart tail = head # Reset tail to head position to start fresh phase = "growing" diff --git a/test/patterns/auto_manual.py b/test/patterns/auto_manual.py index d4c5c8e..a5ec964 100644 --- a/test/patterns/auto_manual.py +++ b/test/patterns/auto_manual.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, duration_ms): @@ -19,7 +19,7 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) print("=" * 50) @@ -29,11 +29,11 @@ def main(): # Test 1: Rainbow in AUTO mode (continuous) print("\nTest 1: Rainbow pattern in AUTO mode (should run continuously)") p.edit("rainbow_auto", { - "pattern": "rainbow", - "brightness": 128, - "delay": 50, + "p": "rainbow", + "b": 128, + "d": 50, "n1": 2, - "auto": True + "a": True, }) p.select("rainbow_auto") print("Running rainbow_auto for 3 seconds...") @@ -43,11 +43,11 @@ def main(): # Test 2: Rainbow in MANUAL mode (one step per tick) print("\nTest 2: Rainbow pattern in MANUAL mode (one step per tick)") p.edit("rainbow_manual", { - "pattern": "rainbow", - "brightness": 128, - "delay": 50, + "p": "rainbow", + "b": 128, + "d": 50, "n1": 2, - "auto": False + "a": False, }) p.select("rainbow_manual") print("Calling tick() 5 times (should advance 5 steps)...") @@ -65,14 +65,14 @@ def main(): # Test 3: Pulse in AUTO mode (continuous cycles) print("\nTest 3: Pulse pattern in AUTO mode (should pulse continuously)") p.edit("pulse_auto", { - "pattern": "pulse", - "brightness": 128, - "delay": 100, + "p": "pulse", + "b": 128, + "d": 100, "n1": 500, # Attack "n2": 200, # Hold "n3": 500, # Decay - "colors": [(255, 0, 0)], - "auto": True + "c": [(255, 0, 0)], + "a": True, }) p.select("pulse_auto") print("Running pulse_auto for 3 seconds...") @@ -82,14 +82,14 @@ def main(): # Test 4: Pulse in MANUAL mode (one cycle then stop) print("\nTest 4: Pulse pattern in MANUAL mode (one cycle then stop)") p.edit("pulse_manual", { - "pattern": "pulse", - "brightness": 128, - "delay": 100, + "p": "pulse", + "b": 128, + "d": 100, "n1": 300, # Attack "n2": 200, # Hold "n3": 300, # Decay - "colors": [(0, 255, 0)], - "auto": False + "c": [(0, 255, 0)], + "a": False, }) p.select("pulse_manual") print("Running pulse_manual until generator stops...") @@ -108,11 +108,11 @@ def main(): # Test 5: Transition in AUTO mode (continuous transitions) print("\nTest 5: Transition pattern in AUTO mode (continuous transitions)") p.edit("transition_auto", { - "pattern": "transition", - "brightness": 128, - "delay": 500, - "colors": [(255, 0, 0), (0, 255, 0), (0, 0, 255)], - "auto": True + "p": "transition", + "b": 128, + "d": 500, + "c": [(255, 0, 0), (0, 255, 0), (0, 0, 255)], + "a": True, }) p.select("transition_auto") print("Running transition_auto for 3 seconds...") @@ -122,11 +122,11 @@ def main(): # Test 6: Transition in MANUAL mode (one transition then stop) print("\nTest 6: Transition pattern in MANUAL mode (one transition then stop)") p.edit("transition_manual", { - "pattern": "transition", - "brightness": 128, - "delay": 500, - "colors": [(255, 0, 0), (0, 255, 0)], - "auto": False + "p": "transition", + "b": 128, + "d": 500, + "c": [(255, 0, 0), (0, 255, 0)], + "a": False, }) p.select("transition_manual") print("Running transition_manual until generator stops...") @@ -145,11 +145,11 @@ def main(): # Test 7: Switching between auto and manual modes print("\nTest 7: Switching between auto and manual modes") p.edit("switch_test", { - "pattern": "rainbow", - "brightness": 128, - "delay": 50, + "p": "rainbow", + "b": 128, + "d": 50, "n1": 2, - "auto": True + "a": True, }) p.select("switch_test") print("Running in auto mode for 1 second...") @@ -157,7 +157,7 @@ def main(): # Switch to manual mode by editing the preset print("Switching to manual mode...") - p.edit("switch_test", {"auto": False}) + p.edit("switch_test", {"a": False}) p.select("switch_test") # Re-select to apply changes print("Calling tick() 3 times in manual mode...") @@ -168,7 +168,7 @@ def main(): # Switch back to auto mode print("Switching back to auto mode...") - p.edit("switch_test", {"auto": True}) + p.edit("switch_test", {"a": True}) p.select("switch_test") print("Running in auto mode for 1 second...") run_for(p, wdt, 1000) @@ -176,7 +176,7 @@ def main(): # Cleanup print("\nCleaning up...") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") p.tick() utime.sleep_ms(100) diff --git a/test/patterns/blink.py b/test/patterns/blink.py index 7e45607..7291dde 100644 --- a/test/patterns/blink.py +++ b/test/patterns/blink.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def main(): @@ -10,15 +10,15 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) - # Create blink preset + # Create blink preset (use short-key fields: p=pattern, b=brightness, d=delay, c=colors) p.edit("test_blink", { - "pattern": "blink", - "brightness": 64, - "delay": 200, - "colors": [(255, 0, 0), (0, 0, 255)] + "p": "blink", + "b": 64, + "d": 200, + "c": [(255, 0, 0), (0, 0, 255)], }) p.select("test_blink") diff --git a/test/patterns/chase.py b/test/patterns/chase.py index 65ef7ab..39c2618 100644 --- a/test/patterns/chase.py +++ b/test/patterns/chase.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, ms): @@ -19,20 +19,20 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) # Test 1: Basic chase (n1=5, n2=5, n3=1, n4=1) print("Test 1: Basic chase (n1=5, n2=5, n3=1, n4=1)") p.edit("chase1", { - "pattern": "chase", - "brightness": 255, - "delay": 200, + "p": "chase", + "b": 255, + "d": 200, "n1": 5, "n2": 5, "n3": 1, "n4": 1, - "colors": [(255, 0, 0), (0, 255, 0)] + "c": [(255, 0, 0), (0, 255, 0)], }) p.select("chase1") run_for(p, wdt, 3000) @@ -40,13 +40,13 @@ def main(): # Test 2: Forward and backward (n3=2, n4=-1) print("Test 2: Forward and backward (n3=2, n4=-1)") p.edit("chase2", { - "pattern": "chase", + "p": "chase", "n1": 3, "n2": 3, "n3": 2, "n4": -1, - "delay": 150, - "colors": [(0, 0, 255), (255, 255, 0)] + "d": 150, + "c": [(0, 0, 255), (255, 255, 0)], }) p.select("chase2") run_for(p, wdt, 3000) @@ -54,13 +54,13 @@ def main(): # Test 3: Large segments (n1=10, n2=5) print("Test 3: Large segments (n1=10, n2=5, n3=3, n4=3)") p.edit("chase3", { - "pattern": "chase", + "p": "chase", "n1": 10, "n2": 5, "n3": 3, "n4": 3, - "delay": 200, - "colors": [(255, 128, 0), (128, 0, 255)] + "d": 200, + "c": [(255, 128, 0), (128, 0, 255)], }) p.select("chase3") run_for(p, wdt, 3000) @@ -68,13 +68,13 @@ def main(): # Test 4: Fast movement (n3=5, n4=5) print("Test 4: Fast movement (n3=5, n4=5)") p.edit("chase4", { - "pattern": "chase", + "p": "chase", "n1": 4, "n2": 4, "n3": 5, "n4": 5, - "delay": 100, - "colors": [(255, 0, 255), (0, 255, 255)] + "d": 100, + "c": [(255, 0, 255), (0, 255, 255)], }) p.select("chase4") run_for(p, wdt, 2000) @@ -82,13 +82,13 @@ def main(): # Test 5: Backward movement (n3=-2, n4=-2) print("Test 5: Backward movement (n3=-2, n4=-2)") p.edit("chase5", { - "pattern": "chase", + "p": "chase", "n1": 6, "n2": 4, "n3": -2, "n4": -2, - "delay": 200, - "colors": [(255, 255, 255), (0, 0, 0)] + "d": 200, + "c": [(255, 255, 255), (0, 0, 0)], }) p.select("chase5") run_for(p, wdt, 3000) @@ -96,13 +96,13 @@ def main(): # Test 6: Alternating forward/backward (n3=3, n4=-2) print("Test 6: Alternating forward/backward (n3=3, n4=-2)") p.edit("chase6", { - "pattern": "chase", + "p": "chase", "n1": 5, "n2": 5, "n3": 3, "n4": -2, - "delay": 250, - "colors": [(255, 0, 0), (0, 255, 0)] + "d": 250, + "c": [(255, 0, 0), (0, 255, 0)], }) p.select("chase6") run_for(p, wdt, 4000) @@ -110,14 +110,14 @@ def main(): # Test 7: Manual mode - advance one step per beat print("Test 7: Manual mode chase (auto=False, n3=2, n4=1)") p.edit("chase_manual", { - "pattern": "chase", + "p": "chase", "n1": 4, "n2": 4, "n3": 2, "n4": 1, - "delay": 200, - "colors": [(255, 255, 0), (0, 255, 255)], - "auto": False + "d": 200, + "c": [(255, 255, 0), (0, 255, 255)], + "a": False, }) p.step = 0 # Reset step counter print(" Advancing pattern with 10 beats (select + tick)...") @@ -131,12 +131,12 @@ def main(): # Test 8: Verify step increments correctly in manual mode print("Test 8: Verify step increments (auto=False)") p.edit("chase_manual2", { - "pattern": "chase", + "p": "chase", "n1": 3, "n2": 3, "n3": 1, "n4": 1, - "auto": False + "a": False, }) p.step = 0 initial_step = p.step @@ -151,7 +151,7 @@ def main(): # Cleanup print("Test complete, turning off") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") run_for(p, wdt, 100) diff --git a/test/patterns/circle.py b/test/patterns/circle.py index 11f104c..2de9d8d 100644 --- a/test/patterns/circle.py +++ b/test/patterns/circle.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, ms): @@ -19,19 +19,19 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) # Test 1: Basic circle (n1=50, n2=100, n3=200, n4=0) print("Test 1: Basic circle (n1=50, n2=100, n3=200, n4=0)") p.edit("circle1", { - "pattern": "circle", - "brightness": 255, + "p": "circle", + "b": 255, "n1": 50, # Head moves 50 LEDs/second "n2": 100, # Max length 100 LEDs "n3": 200, # Tail moves 200 LEDs/second "n4": 0, # Min length 0 LEDs - "colors": [(255, 0, 0)] # Red + "c": [(255, 0, 0)], # Red }) p.select("circle1") run_for(p, wdt, 5000) @@ -39,12 +39,12 @@ def main(): # Test 2: Slow growth, fast shrink (n1=20, n2=50, n3=100, n4=0) print("Test 2: Slow growth, fast shrink (n1=20, n2=50, n3=100, n4=0)") p.edit("circle2", { - "pattern": "circle", + "p": "circle", "n1": 20, "n2": 50, "n3": 100, "n4": 0, - "colors": [(0, 255, 0)] # Green + "c": [(0, 255, 0)], # Green }) p.select("circle2") run_for(p, wdt, 5000) @@ -52,12 +52,12 @@ def main(): # Test 3: Fast growth, slow shrink (n1=100, n2=30, n3=20, n4=0) print("Test 3: Fast growth, slow shrink (n1=100, n2=30, n3=20, n4=0)") p.edit("circle3", { - "pattern": "circle", + "p": "circle", "n1": 100, "n2": 30, "n3": 20, "n4": 0, - "colors": [(0, 0, 255)] # Blue + "c": [(0, 0, 255)], # Blue }) p.select("circle3") run_for(p, wdt, 5000) @@ -65,12 +65,12 @@ def main(): # Test 4: With minimum length (n1=50, n2=40, n3=100, n4=10) print("Test 4: With minimum length (n1=50, n2=40, n3=100, n4=10)") p.edit("circle4", { - "pattern": "circle", + "p": "circle", "n1": 50, "n2": 40, "n3": 100, "n4": 10, - "colors": [(255, 255, 0)] # Yellow + "c": [(255, 255, 0)], # Yellow }) p.select("circle4") run_for(p, wdt, 5000) @@ -78,12 +78,12 @@ def main(): # Test 5: Very fast (n1=200, n2=20, n3=200, n4=0) print("Test 5: Very fast (n1=200, n2=20, n3=200, n4=0)") p.edit("circle5", { - "pattern": "circle", + "p": "circle", "n1": 200, "n2": 20, "n3": 200, "n4": 0, - "colors": [(255, 0, 255)] # Magenta + "c": [(255, 0, 255)], # Magenta }) p.select("circle5") run_for(p, wdt, 3000) @@ -91,19 +91,19 @@ def main(): # Test 6: Very slow (n1=10, n2=25, n3=10, n4=0) print("Test 6: Very slow (n1=10, n2=25, n3=10, n4=0)") p.edit("circle6", { - "pattern": "circle", + "p": "circle", "n1": 10, "n2": 25, "n3": 10, "n4": 0, - "colors": [(0, 255, 255)] # Cyan + "c": [(0, 255, 255)], # Cyan }) p.select("circle6") run_for(p, wdt, 5000) # Cleanup print("Test complete, turning off") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") run_for(p, wdt, 100) diff --git a/test/patterns/off.py b/test/patterns/off.py index 995211c..e85a701 100644 --- a/test/patterns/off.py +++ b/test/patterns/off.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def main(): @@ -10,11 +10,11 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) - # Create an "off" preset - p.edit("test_off", {"pattern": "off"}) + # Create an "off" preset (use short-key field `p` for pattern) + p.edit("test_off", {"p": "off"}) p.select("test_off") start = utime.ticks_ms() diff --git a/test/patterns/on.py b/test/patterns/on.py index 7b10f73..44c82c1 100644 --- a/test/patterns/on.py +++ b/test/patterns/on.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def main(): @@ -10,17 +10,19 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) - # Create presets for on and off + # Create presets for on and off using the short-key fields that Presets expects + # Preset fields: + # p = pattern name, b = brightness, d = delay, c = list of (r,g,b) colors p.edit("test_on", { - "pattern": "on", - "brightness": 64, - "delay": 120, - "colors": [(255, 0, 0), (0, 0, 255)] + "p": "on", + "b": 64, + "d": 120, + "c": [(255, 0, 0), (0, 0, 255)], }) - p.edit("test_off", {"pattern": "off"}) + p.edit("test_off", {"p": "off"}) # ON phase p.select("test_on") diff --git a/test/patterns/pulse.py b/test/patterns/pulse.py index 2e46e80..708b112 100644 --- a/test/patterns/pulse.py +++ b/test/patterns/pulse.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, ms): @@ -19,20 +19,20 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) # Test 1: Simple single-color pulse print("Test 1: Single-color pulse (attack=500, hold=500, decay=500, delay=500)") p.edit("pulse1", { - "pattern": "pulse", - "brightness": 255, - "colors": [(255, 0, 0)], + "p": "pulse", + "b": 255, + "c": [(255, 0, 0)], "n1": 500, # attack ms "n2": 500, # hold ms "n3": 500, # decay ms - "delay": 500, # delay ms between pulses - "auto": True + "d": 500, # delay ms between pulses + "a": True, }) p.select("pulse1") run_for(p, wdt, 5000) @@ -40,12 +40,12 @@ def main(): # Test 2: Faster pulse print("Test 2: Fast pulse (attack=100, hold=100, decay=100, delay=100)") p.edit("pulse2", { - "pattern": "pulse", + "p": "pulse", "n1": 100, "n2": 100, "n3": 100, - "delay": 100, - "colors": [(0, 255, 0)] + "d": 100, + "c": [(0, 255, 0)], }) p.select("pulse2") run_for(p, wdt, 4000) @@ -53,13 +53,13 @@ def main(): # Test 3: Multi-color pulse cycle print("Test 3: Multi-color pulse (red -> green -> blue)") p.edit("pulse3", { - "pattern": "pulse", + "p": "pulse", "n1": 300, "n2": 300, "n3": 300, - "delay": 200, - "colors": [(255, 0, 0), (0, 255, 0), (0, 0, 255)], - "auto": True + "d": 200, + "c": [(255, 0, 0), (0, 255, 0), (0, 0, 255)], + "a": True, }) p.select("pulse3") run_for(p, wdt, 6000) @@ -67,13 +67,13 @@ def main(): # Test 4: One-shot pulse (auto=False) print("Test 4: Single pulse, auto=False") p.edit("pulse4", { - "pattern": "pulse", + "p": "pulse", "n1": 400, "n2": 0, "n3": 400, - "delay": 0, - "colors": [(255, 255, 255)], - "auto": False + "d": 0, + "c": [(255, 255, 255)], + "a": False, }) p.select("pulse4") # Run long enough to allow one full pulse cycle @@ -81,7 +81,7 @@ def main(): # Cleanup print("Test complete, turning off") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") run_for(p, wdt, 200) diff --git a/test/patterns/rainbow.py b/test/patterns/rainbow.py index 73a6493..7773371 100644 --- a/test/patterns/rainbow.py +++ b/test/patterns/rainbow.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, ms): @@ -19,17 +19,17 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) # Test 1: Basic rainbow with auto=True (continuous) print("Test 1: Basic rainbow (auto=True, n1=1)") p.edit("rainbow1", { - "pattern": "rainbow", - "brightness": 255, - "delay": 100, + "p": "rainbow", + "b": 255, + "d": 100, "n1": 1, - "auto": True + "a": True, }) p.select("rainbow1") run_for(p, wdt, 3000) @@ -37,10 +37,10 @@ def main(): # Test 2: Fast rainbow print("Test 2: Fast rainbow (low delay, n1=1)") p.edit("rainbow2", { - "pattern": "rainbow", - "delay": 50, + "p": "rainbow", + "d": 50, "n1": 1, - "auto": True + "a": True, }) p.select("rainbow2") run_for(p, wdt, 2000) @@ -48,10 +48,10 @@ def main(): # Test 3: Slow rainbow print("Test 3: Slow rainbow (high delay, n1=1)") p.edit("rainbow3", { - "pattern": "rainbow", - "delay": 500, + "p": "rainbow", + "d": 500, "n1": 1, - "auto": True + "a": True, }) p.select("rainbow3") run_for(p, wdt, 3000) @@ -59,11 +59,11 @@ def main(): # Test 4: Low brightness rainbow print("Test 4: Low brightness rainbow (n1=1)") p.edit("rainbow4", { - "pattern": "rainbow", - "brightness": 64, - "delay": 100, + "p": "rainbow", + "b": 64, + "d": 100, "n1": 1, - "auto": True + "a": True, }) p.select("rainbow4") run_for(p, wdt, 2000) @@ -71,11 +71,11 @@ def main(): # Test 5: Single-step rainbow (auto=False) print("Test 5: Single-step rainbow (auto=False, n1=1)") p.edit("rainbow5", { - "pattern": "rainbow", - "brightness": 255, - "delay": 100, + "p": "rainbow", + "b": 255, + "d": 100, "n1": 1, - "auto": False + "a": False, }) p.step = 0 for i in range(10): @@ -88,9 +88,9 @@ def main(): # Test 6: Verify step updates correctly print("Test 6: Verify step updates (auto=False, n1=1)") p.edit("rainbow6", { - "pattern": "rainbow", + "p": "rainbow", "n1": 1, - "auto": False + "a": False, }) initial_step = p.step p.select("rainbow6") @@ -101,11 +101,11 @@ def main(): # Test 7: Fast step increment (n1=5) print("Test 7: Fast rainbow (n1=5, auto=True)") p.edit("rainbow7", { - "pattern": "rainbow", - "brightness": 255, - "delay": 100, + "p": "rainbow", + "b": 255, + "d": 100, "n1": 5, - "auto": True + "a": True, }) p.select("rainbow7") run_for(p, wdt, 2000) @@ -113,9 +113,9 @@ def main(): # Test 8: Very fast step increment (n1=10) print("Test 8: Very fast rainbow (n1=10, auto=True)") p.edit("rainbow8", { - "pattern": "rainbow", + "p": "rainbow", "n1": 10, - "auto": True + "a": True, }) p.select("rainbow8") run_for(p, wdt, 2000) @@ -123,9 +123,9 @@ def main(): # Test 9: Verify n1 controls step increment (auto=False) print("Test 9: Verify n1 step increment (auto=False, n1=5)") p.edit("rainbow9", { - "pattern": "rainbow", + "p": "rainbow", "n1": 5, - "auto": False + "a": False, }) p.step = 0 initial_step = p.step @@ -141,7 +141,7 @@ def main(): # Cleanup print("Test complete, turning off") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") run_for(p, wdt, 100) diff --git a/test/patterns/transition.py b/test/patterns/transition.py index 3eb9094..00149c0 100644 --- a/test/patterns/transition.py +++ b/test/patterns/transition.py @@ -2,7 +2,7 @@ import utime from machine import WDT from settings import Settings -from patterns import Patterns +from presets import Presets def run_for(p, wdt, ms): @@ -19,17 +19,17 @@ def main(): pin = s.get("led_pin", 10) num = s.get("num_leds", 30) - p = Patterns(pin=pin, num_leds=num) + p = Presets(pin=pin, num_leds=num) wdt = WDT(timeout=10000) # Test 1: Simple two-color transition print("Test 1: Two-color transition (red <-> blue, delay=1000)") p.edit("transition1", { - "pattern": "transition", - "brightness": 255, - "delay": 1000, # transition duration - "colors": [(255, 0, 0), (0, 0, 255)], - "auto": True + "p": "transition", + "b": 255, + "d": 1000, # transition duration + "c": [(255, 0, 0), (0, 0, 255)], + "a": True, }) p.select("transition1") run_for(p, wdt, 6000) @@ -37,10 +37,10 @@ def main(): # Test 2: Multi-color transition print("Test 2: Multi-color transition (red -> green -> blue -> white)") p.edit("transition2", { - "pattern": "transition", - "delay": 800, - "colors": [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255)], - "auto": True + "p": "transition", + "d": 800, + "c": [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255)], + "a": True, }) p.select("transition2") run_for(p, wdt, 8000) @@ -48,10 +48,10 @@ def main(): # Test 3: One-shot transition (auto=False) print("Test 3: One-shot transition (auto=False)") p.edit("transition3", { - "pattern": "transition", - "delay": 1000, - "colors": [(255, 0, 0), (0, 255, 0)], - "auto": False + "p": "transition", + "d": 1000, + "c": [(255, 0, 0), (0, 255, 0)], + "a": False, }) p.select("transition3") # Run long enough for a single transition step @@ -60,17 +60,17 @@ def main(): # Test 4: Single-color behavior (should just stay on) print("Test 4: Single-color transition (should hold color)") p.edit("transition4", { - "pattern": "transition", - "colors": [(0, 0, 255)], - "delay": 500, - "auto": True + "p": "transition", + "c": [(0, 0, 255)], + "d": 500, + "a": True, }) p.select("transition4") run_for(p, wdt, 3000) # Cleanup print("Test complete, turning off") - p.edit("cleanup_off", {"pattern": "off"}) + p.edit("cleanup_off", {"p": "off"}) p.select("cleanup_off") run_for(p, wdt, 200) diff --git a/test/test_espnow_receive.py b/test/test_espnow_receive.py index adb7584..8e2bd9c 100644 --- a/test/test_espnow_receive.py +++ b/test/test_espnow_receive.py @@ -3,7 +3,7 @@ import json import utime from settings import Settings -from patterns import Patterns +from presets import Presets from utils import convert_and_reorder_colors @@ -93,7 +93,7 @@ def test_version_check(): """Test that messages with wrong version are rejected.""" print("Test 1: Version check") settings = Settings() - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -119,7 +119,7 @@ def test_preset_creation(): """Test preset creation from ESPNow messages.""" print("\nTest 2: Preset creation") settings = Settings() - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -164,7 +164,7 @@ def test_color_conversion(): print("\nTest 3: Color conversion") settings = Settings() settings["color_order"] = "rgb" # Default RGB order - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -190,7 +190,7 @@ def test_color_conversion(): # Test GRB order settings["color_order"] = "grb" - patterns2 = Patterns(settings["led_pin"], settings["num_leds"]) + patterns2 = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow2 = MockESPNow() msg2 = { "v": "1", @@ -213,7 +213,7 @@ def test_preset_update(): """Test that editing an existing preset updates it.""" print("\nTest 4: Preset update") settings = Settings() - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -256,7 +256,7 @@ def test_select(): print("\nTest 5: Preset selection") settings = Settings() settings["name"] = "device1" - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -291,7 +291,7 @@ def test_full_message(): print("\nTest 6: Full message (presets + select)") settings = Settings() settings["name"] = "test_device" - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -331,7 +331,7 @@ def test_switch_presets(): print("\nTest 7: Switch between presets") settings = Settings() settings["name"] = "switch_device" - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -427,7 +427,7 @@ def test_beat_functionality(): print("\nTest 8: Beat functionality") settings = Settings() settings["name"] = "beat_device" - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -551,7 +551,7 @@ def test_select_with_step(): print("\nTest 9: Select with step value") settings = Settings() settings["name"] = "step_device" - patterns = Patterns(settings["led_pin"], settings["num_leds"]) + patterns = Presets(settings["led_pin"], settings["num_leds"]) mock_espnow = MockESPNow() wdt = get_wdt() @@ -602,7 +602,7 @@ def test_select_with_step(): print(" ✓ Step preserved when selecting same preset without step (tick advances it)") # Select different preset with step - patterns.edit("other_preset", {"pattern": "rainbow", "auto": False}) + patterns.edit("other_preset", {"p": "rainbow", "a": False}) mock_espnow.clear() msg4 = { "v": "1",