Use shortened preset fields in driver

Switch led-driver patterns and main loop to use compact preset keys (p, d, b, c, a, n1..n6) and remove unused settings defaults.
This commit is contained in:
2026-01-28 23:28:54 +13:00
parent 02db2b629c
commit 337e8c9906
3 changed files with 47 additions and 49 deletions

View File

@@ -9,7 +9,7 @@ import json
settings = Settings() settings = Settings()
print(settings) print(settings)
patterns = Patterns(settings["led_pin"], settings["num_leds"], selected=settings["pattern"]) patterns = Patterns(settings["led_pin"], settings["num_leds"])
wdt = WDT(timeout=10000) wdt = WDT(timeout=10000)
wdt.feed() wdt.feed()
@@ -30,11 +30,12 @@ while True:
data = json.loads(msg) data = json.loads(msg)
if data["v"] != "1": if data["v"] != "1":
continue continue
print(data)
if "presets" in data: if "presets" in data:
for name, preset_data in data["presets"].items(): for name, preset_data in data["presets"].items():
# Convert hex color strings to RGB tuples and reorder based on device color order # Convert hex color strings to RGB tuples and reorder based on device color order
if "colors" in preset_data: if "c" in preset_data:
preset_data["colors"] = convert_and_reorder_colors(preset_data["colors"], settings) preset_data["c"] = convert_and_reorder_colors(preset_data["c"], settings)
patterns.edit(name, preset_data) patterns.edit(name, preset_data)
if settings.get("name") in data.get("select", {}): if settings.get("name") in data.get("select", {}):
select_list = data["select"][settings.get("name")] select_list = data["select"][settings.get("name")]

View File

@@ -25,11 +25,11 @@ param_mapping = {
class Preset: class Preset:
def __init__(self, data): def __init__(self, data):
# Set default values for all preset attributes # Set default values for all preset attributes
self.pattern = "off" self.p = "off"
self.delay = 100 self.d = 100
self.brightness = 127 self.b = 127
self.colors = [(255, 255, 255)] self.c = [(255, 255, 255)]
self.auto = True self.a = True
self.n1 = 0 self.n1 = 0
self.n2 = 0 self.n2 = 0
self.n3 = 0 self.n3 = 0
@@ -48,15 +48,15 @@ class Preset:
return True return True
class Patterns: class Patterns:
def __init__(self, pin, num_leds, brightness=127, selected="off", delay=100): def __init__(self, pin, num_leds):
self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds) self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds)
self.num_leds = num_leds self.num_leds = num_leds
self.brightness = brightness
self.step = 0 self.step = 0
self.selected = selected
self.generator = None self.generator = None
self.presets = {} self.presets = {}
self.selected = None
# Register all pattern methods # Register all pattern methods
self.patterns = { self.patterns = {
@@ -70,7 +70,6 @@ class Patterns:
"circle": self.circle, "circle": self.circle,
} }
self.select(self.selected)
def edit(self, name, data): def edit(self, name, data):
"""Create or update a preset with the given name.""" """Create or update a preset with the given name."""
@@ -99,13 +98,13 @@ class Patterns:
def select(self, preset_name, step=None): def select(self, preset_name, step=None):
if preset_name in self.presets: if preset_name in self.presets:
preset = self.presets[preset_name] preset = self.presets[preset_name]
if preset.pattern in self.patterns: if preset.p in self.patterns:
# Set step value if explicitly provided # Set step value if explicitly provided
if step is not None: if step is not None:
self.step = step self.step = step
elif preset.pattern == "off" or self.selected != preset_name: elif preset.p == "off" or self.selected != preset_name:
self.step = 0 self.step = 0
self.generator = self.patterns[preset.pattern](preset) self.generator = self.patterns[preset.p](preset)
self.selected = preset_name # Store the preset name, not the object self.selected = preset_name # Store the preset name, not the object
return True return True
# If preset doesn't exist or pattern not found, default to "off" # If preset doesn't exist or pattern not found, default to "off"
@@ -136,9 +135,9 @@ class Patterns:
self.fill((0, 0, 0)) self.fill((0, 0, 0))
def on(self, preset): def on(self, preset):
colors = preset.colors colors = preset.c
color = colors[0] if colors else (255, 255, 255) color = colors[0] if colors else (255, 255, 255)
self.fill(self.apply_brightness(color, preset.brightness)) self.fill(self.apply_brightness(color, preset.b))
def wheel(self, pos): def wheel(self, pos):
if pos < 85: if pos < 85:
@@ -156,10 +155,10 @@ class Patterns:
while True: while True:
current_time = utime.ticks_ms() current_time = utime.ticks_ms()
if utime.ticks_diff(current_time, last_update) >= preset.delay: if utime.ticks_diff(current_time, last_update) >= preset.d:
if state: if state:
color = preset.colors[0] if preset.colors else (255, 255, 255) color = preset.c[0] if preset.c else (255, 255, 255)
self.fill(self.apply_brightness(color, preset.brightness)) self.fill(self.apply_brightness(color, preset.b))
else: else:
self.fill((0, 0, 0)) self.fill((0, 0, 0))
state = not state state = not state
@@ -172,10 +171,10 @@ class Patterns:
step_amount = max(1, int(preset.n1)) # n1 controls step increment step_amount = max(1, int(preset.n1)) # n1 controls step increment
# If auto is False, run a single step and then stop # If auto is False, run a single step and then stop
if not preset.auto: if not preset.a:
for i in range(self.num_leds): for i in range(self.num_leds):
rc_index = (i * 256 // self.num_leds) + step rc_index = (i * 256 // self.num_leds) + step
self.n[i] = self.apply_brightness(self.wheel(rc_index & 255), preset.brightness) self.n[i] = self.apply_brightness(self.wheel(rc_index & 255), preset.b)
self.n.write() self.n.write()
# Increment step by n1 for next manual call # Increment step by n1 for next manual call
self.step = (step + step_amount) % 256 self.step = (step + step_amount) % 256
@@ -187,11 +186,11 @@ class Patterns:
while True: while True:
current_time = utime.ticks_ms() current_time = utime.ticks_ms()
sleep_ms = max(1, int(preset.delay)) # Get delay from preset sleep_ms = max(1, int(preset.d)) # Get delay from preset
if utime.ticks_diff(current_time, last_update) >= sleep_ms: if utime.ticks_diff(current_time, last_update) >= sleep_ms:
for i in range(self.num_leds): for i in range(self.num_leds):
rc_index = (i * 256 // self.num_leds) + step rc_index = (i * 256 // self.num_leds) + step
self.n[i] = self.apply_brightness(self.wheel(rc_index & 255), preset.brightness) self.n[i] = self.apply_brightness(self.wheel(rc_index & 255), preset.b)
self.n.write() self.n.write()
step = (step + step_amount) % 256 step = (step + step_amount) % 256
self.step = step self.step = step
@@ -203,7 +202,7 @@ class Patterns:
self.off() self.off()
# Get colors from preset # Get colors from preset
colors = preset.colors colors = preset.c
if not colors: if not colors:
colors = [(255, 255, 255)] colors = [(255, 255, 255)]
@@ -216,7 +215,7 @@ class Patterns:
attack_ms = max(0, int(preset.n1)) # Attack time in ms attack_ms = max(0, int(preset.n1)) # Attack time in ms
hold_ms = max(0, int(preset.n2)) # Hold time in ms hold_ms = max(0, int(preset.n2)) # Hold time in ms
decay_ms = max(0, int(preset.n3)) # Decay time in ms decay_ms = max(0, int(preset.n3)) # Decay time in ms
delay_ms = max(0, int(preset.delay)) delay_ms = max(0, int(preset.d))
total_ms = attack_ms + hold_ms + decay_ms + delay_ms total_ms = attack_ms + hold_ms + decay_ms + delay_ms
if total_ms <= 0: if total_ms <= 0:
@@ -231,16 +230,16 @@ class Patterns:
# Attack: fade 0 -> 1 # Attack: fade 0 -> 1
factor = elapsed / attack_ms factor = elapsed / attack_ms
color = tuple(int(c * factor) for c in base_color) color = tuple(int(c * factor) for c in base_color)
self.fill(self.apply_brightness(color, preset.brightness)) self.fill(self.apply_brightness(color, preset.b))
elif elapsed < attack_ms + hold_ms: elif elapsed < attack_ms + hold_ms:
# Hold: full brightness # Hold: full brightness
self.fill(self.apply_brightness(base_color, preset.brightness)) self.fill(self.apply_brightness(base_color, preset.b))
elif elapsed < attack_ms + hold_ms + decay_ms and decay_ms > 0: elif elapsed < attack_ms + hold_ms + decay_ms and decay_ms > 0:
# Decay: fade 1 -> 0 # Decay: fade 1 -> 0
dec_elapsed = elapsed - attack_ms - hold_ms dec_elapsed = elapsed - attack_ms - hold_ms
factor = max(0.0, 1.0 - (dec_elapsed / decay_ms)) factor = max(0.0, 1.0 - (dec_elapsed / decay_ms))
color = tuple(int(c * factor) for c in base_color) color = tuple(int(c * factor) for c in base_color)
self.fill(self.apply_brightness(color, preset.brightness)) self.fill(self.apply_brightness(color, preset.b))
elif elapsed < total_ms: elif elapsed < total_ms:
# Delay phase: LEDs off between pulses # Delay phase: LEDs off between pulses
self.fill((0, 0, 0)) self.fill((0, 0, 0))
@@ -248,7 +247,7 @@ class Patterns:
# End of cycle, move to next color and restart timing # End of cycle, move to next color and restart timing
color_index += 1 color_index += 1
cycle_start = now cycle_start = now
if not preset.auto: if not preset.a:
break break
# Skip drawing this tick, start next cycle # Skip drawing this tick, start next cycle
yield yield
@@ -259,7 +258,7 @@ class Patterns:
def transition(self, preset): def transition(self, preset):
"""Transition between colors, blending over `delay` ms.""" """Transition between colors, blending over `delay` ms."""
colors = preset.colors colors = preset.c
if not colors: if not colors:
self.off() self.off()
yield yield
@@ -268,7 +267,7 @@ class Patterns:
# Only one color: just keep it on # Only one color: just keep it on
if len(colors) == 1: if len(colors) == 1:
while True: while True:
self.fill(self.apply_brightness(colors[0], preset.brightness)) self.fill(self.apply_brightness(colors[0], preset.b))
yield yield
return return
@@ -283,15 +282,15 @@ class Patterns:
c1 = colors[color_index % len(colors)] c1 = colors[color_index % len(colors)]
c2 = colors[(color_index + 1) % len(colors)] c2 = colors[(color_index + 1) % len(colors)]
duration = max(10, int(preset.delay)) # At least 10ms duration = max(10, int(preset.d)) # At least 10ms
now = utime.ticks_ms() now = utime.ticks_ms()
elapsed = utime.ticks_diff(now, start_time) elapsed = utime.ticks_diff(now, start_time)
if elapsed >= duration: if elapsed >= duration:
# End of this transition step # End of this transition step
if not preset.auto: if not preset.a:
# One-shot: transition from first to second color only # One-shot: transition from first to second color only
self.fill(self.apply_brightness(c2, preset.brightness)) self.fill(self.apply_brightness(c2, preset.b))
break break
# Auto: move to next pair # Auto: move to next pair
color_index = (color_index + 1) % len(colors) color_index = (color_index + 1) % len(colors)
@@ -304,14 +303,14 @@ class Patterns:
interpolated = tuple( interpolated = tuple(
int(c1[i] + (c2[i] - c1[i]) * factor) for i in range(3) int(c1[i] + (c2[i] - c1[i]) * factor) for i in range(3)
) )
self.fill(self.apply_brightness(interpolated, preset.brightness)) self.fill(self.apply_brightness(interpolated, preset.b))
yield yield
def chase(self, preset): def chase(self, preset):
"""Chase pattern: n1 LEDs of color0, n2 LEDs of color1, repeating. """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)""" Moves by n3 on even steps, n4 on odd steps (n3/n4 can be positive or negative)"""
colors = preset.colors colors = preset.c
if len(colors) < 1: if len(colors) < 1:
# Need at least 1 color # Need at least 1 color
return return
@@ -327,8 +326,8 @@ class Patterns:
color0 = colors[0] color0 = colors[0]
color1 = colors[1] color1 = colors[1]
color0 = self.apply_brightness(color0, preset.brightness) color0 = self.apply_brightness(color0, preset.b)
color1 = self.apply_brightness(color1, preset.brightness) color1 = self.apply_brightness(color1, preset.b)
n1 = max(1, int(preset.n1)) # LEDs of color 0 n1 = max(1, int(preset.n1)) # LEDs of color 0
n2 = max(1, int(preset.n2)) # LEDs of color 1 n2 = max(1, int(preset.n2)) # LEDs of color 1
@@ -354,7 +353,7 @@ class Patterns:
position += max_pos position += max_pos
# If auto is False, run a single step and then stop # If auto is False, run a single step and then stop
if not preset.auto: if not preset.a:
# Clear all LEDs # Clear all LEDs
self.n.fill((0, 0, 0)) self.n.fill((0, 0, 0))
@@ -381,8 +380,9 @@ class Patterns:
return return
# Auto mode: continuous loop # Auto mode: continuous loop
last_update = utime.ticks_ms() # Use transition_duration for timing and force the first update to happen immediately
transition_duration = max(10, int(preset.delay)) transition_duration = max(10, int(preset.d))
last_update = utime.ticks_ms() - transition_duration
while True: while True:
current_time = utime.ticks_ms() current_time = utime.ticks_ms()
@@ -445,7 +445,7 @@ class Patterns:
phase = "growing" # "growing", "shrinking", or "off" phase = "growing" # "growing", "shrinking", or "off"
colors = preset.colors colors = preset.colors
color = self.apply_brightness(colors[0] if colors else (255, 255, 255), preset.brightness) color = self.apply_brightness(colors[0] if colors else (255, 255, 255), preset.b)
while True: while True:
current_time = utime.ticks_ms() current_time = utime.ticks_ms()

View File

@@ -14,13 +14,10 @@ class Settings(dict):
def set_defaults(self): def set_defaults(self):
self["led_pin"] = 10 self["led_pin"] = 10
self["num_leds"] = 50 self["num_leds"] = 50
self["pattern"] = "on"
self["delay"] = 100
self["brightness"] = 10
self["color_order"] = "rgb" self["color_order"] = "rgb"
self["name"] = f"led-{ubinascii.hexlify(network.WLAN(network.AP_IF).config('mac')).decode()}" self["name"] = f"led-{ubinascii.hexlify(network.WLAN(network.AP_IF).config('mac')).decode()}"
self["ap_password"] = ""
self["id"] = 0
self["debug"] = False self["debug"] = False
def save(self): def save(self):