Rename patterns module to presets
Rename the driver module and update imports so tests and main entry use the new presets naming, while moving Preset to its own file. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
12
src/main.py
12
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)
|
||||
|
||||
24
src/preset.py
Normal file
24
src/preset.py
Normal file
@@ -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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user