132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
from machine import Pin
|
|
from neopixel import NeoPixel
|
|
import utime
|
|
import random
|
|
import _thread
|
|
import asyncio
|
|
from patterns_base import Patterns as PatternsBase
|
|
|
|
# Short-key parameter mapping for convenience setters
|
|
param_mapping = {
|
|
"pt": "selected",
|
|
"pa": "selected",
|
|
"cl": "colors",
|
|
"br": "brightness",
|
|
"dl": "delay",
|
|
"nl": "num_leds",
|
|
"co": "color_order",
|
|
"lp": "led_pin",
|
|
"n1": "n1",
|
|
"n2": "n2",
|
|
"n3": "n3",
|
|
"n4": "n4",
|
|
"n5": "n5",
|
|
"n6": "n6",
|
|
}
|
|
|
|
class Patterns(PatternsBase):
|
|
def __init__(self, pin, num_leds, color1=(0,0,0), color2=(0,0,0), brightness=127, selected="rainbow_cycle", delay=100):
|
|
super().__init__(pin, num_leds, color1, color2, brightness, selected, delay)
|
|
self.patterns = {
|
|
"off": self.off,
|
|
"on" : self.on,
|
|
"blink": self.blink,
|
|
"rainbow": self.rainbow,
|
|
"pulse": self.pulse,
|
|
}
|
|
|
|
|
|
def blink(self):
|
|
self.stopped = False
|
|
self.running = True
|
|
while self.running:
|
|
self.fill(self.apply_brightness(self.colors[0]))
|
|
utime.sleep_ms(self.delay)
|
|
self.fill((0, 0, 0))
|
|
utime.sleep_ms(self.delay)
|
|
self.running = False
|
|
self.stopped = True
|
|
|
|
|
|
def rainbow(self):
|
|
self.stopped = False
|
|
self.running = True
|
|
step = self.pattern_step % 256
|
|
while self.running:
|
|
for i in range(self.num_leds):
|
|
rc_index = (i * 256 // self.num_leds) + step
|
|
self.n[i] = self.apply_brightness(self.wheel(rc_index & 255))
|
|
self.n.write()
|
|
step = (step + 1) % 256
|
|
self.pattern_step = step
|
|
# faster animation even with larger delays; scale delay
|
|
sleep_ms = max(1, int(self.delay / 5))
|
|
utime.sleep_ms(sleep_ms)
|
|
self.running = False
|
|
self.stopped = True
|
|
|
|
|
|
def pulse(self):
|
|
self.stopped = False
|
|
self.running = True
|
|
self.off()
|
|
|
|
# Get timing parameters with defaults if not set
|
|
attack_ms = getattr(self, 'n1', 200) # Attack time in ms
|
|
hold_ms = getattr(self, 'n2', 200) # Hold time in ms
|
|
decay_ms = getattr(self, 'n3', 200) # Decay time in ms
|
|
|
|
base_color = self.colors[0] if self.colors else (255, 255, 255)
|
|
update_interval = 10 # Update every ~10ms for smoothness
|
|
|
|
while self.running:
|
|
cycle_start = utime.ticks_ms()
|
|
|
|
# Attack phase: fade from 0 to full brightness
|
|
if attack_ms > 0:
|
|
attack_start = utime.ticks_ms()
|
|
last_update = attack_start
|
|
while self.running and utime.ticks_diff(utime.ticks_ms(), attack_start) < attack_ms:
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last_update) >= update_interval:
|
|
elapsed = utime.ticks_diff(now, attack_start)
|
|
brightness_factor = min(1.0, elapsed / attack_ms)
|
|
color = tuple(int(c * brightness_factor) for c in base_color)
|
|
self.fill(self.apply_brightness(color))
|
|
last_update = now
|
|
|
|
# Hold phase: maintain full brightness
|
|
if hold_ms > 0 and self.running:
|
|
self.fill(self.apply_brightness(base_color))
|
|
hold_start = utime.ticks_ms()
|
|
while self.running and utime.ticks_diff(utime.ticks_ms(), hold_start) < hold_ms:
|
|
pass
|
|
|
|
# Decay phase: fade from full brightness to 0
|
|
if decay_ms > 0:
|
|
decay_start = utime.ticks_ms()
|
|
last_update = decay_start
|
|
while self.running and utime.ticks_diff(utime.ticks_ms(), decay_start) < decay_ms:
|
|
now = utime.ticks_ms()
|
|
if utime.ticks_diff(now, last_update) >= update_interval:
|
|
elapsed = utime.ticks_diff(now, decay_start)
|
|
brightness_factor = max(0.0, 1.0 - (elapsed / decay_ms))
|
|
color = tuple(int(c * brightness_factor) for c in base_color)
|
|
self.fill(self.apply_brightness(color))
|
|
last_update = now
|
|
|
|
# If delay is 0, run only once and exit
|
|
if self.delay == 0:
|
|
break
|
|
|
|
# Ensure the cycle takes exactly delay milliseconds before restarting
|
|
if self.running:
|
|
self.off()
|
|
wait_until = utime.ticks_add(cycle_start, self.delay)
|
|
while self.running and utime.ticks_diff(wait_until, utime.ticks_ms()) > 0:
|
|
pass
|
|
|
|
self.running = False
|
|
self.stopped = True
|
|
|