Compare commits
2 Commits
059bd41a59
...
a0b85e57a1
| Author | SHA1 | Date | |
|---|---|---|---|
| a0b85e57a1 | |||
| 7547efe7fd |
232
src/patterns.py
232
src/patterns.py
@@ -1,4 +1,4 @@
|
|||||||
from machine import Pin
|
from machine import Pin, WDT
|
||||||
from neopixel import NeoPixel
|
from neopixel import NeoPixel
|
||||||
import utime
|
import utime
|
||||||
import random
|
import random
|
||||||
@@ -14,17 +14,12 @@ class Patterns:
|
|||||||
self.patterns = {
|
self.patterns = {
|
||||||
"off": self.off,
|
"off": self.off,
|
||||||
"on" : self.on,
|
"on" : self.on,
|
||||||
"color_wipe": self.color_wipe_step,
|
|
||||||
"rainbow_cycle": self.rainbow_cycle_step,
|
"rainbow_cycle": self.rainbow_cycle_step,
|
||||||
"theater_chase": self.theater_chase_step,
|
"theater_chase": self.theater_chase_step,
|
||||||
"blink": self.blink_step,
|
"blink": self.blink_step,
|
||||||
"random_color_wipe": self.random_color_wipe_step,
|
|
||||||
"random_rainbow_cycle": self.random_rainbow_cycle_step,
|
|
||||||
"random_theater_chase": self.random_theater_chase_step,
|
|
||||||
"random_blink": self.random_blink_step,
|
|
||||||
"color_transition": self.color_transition_step, # Added new pattern
|
"color_transition": self.color_transition_step, # Added new pattern
|
||||||
"flicker": self.flicker_step,
|
"flicker": self.flicker_step,
|
||||||
"external": None
|
"radiate": self.radiate,
|
||||||
}
|
}
|
||||||
self.selected = selected
|
self.selected = selected
|
||||||
# Ensure colors list always starts with at least two for robust transition handling
|
# Ensure colors list always starts with at least two for robust transition handling
|
||||||
@@ -39,6 +34,17 @@ class Patterns:
|
|||||||
self.current_color = self.colors[self.current_color_idx] # The actual blended color
|
self.current_color = self.colors[self.current_color_idx] # The actual blended color
|
||||||
|
|
||||||
self.hold_start_time = utime.ticks_ms() # Time when the current color hold started
|
self.hold_start_time = utime.ticks_ms() # Time when the current color hold started
|
||||||
|
|
||||||
|
# Radiate pattern attributes
|
||||||
|
self.n1 = 10 # Distance between nodes
|
||||||
|
self.n2 = 0 # Unused
|
||||||
|
self.n3 = 500 # Time to radiate out in ms
|
||||||
|
self.n4 = 500 # Time to radiate in in ms
|
||||||
|
self.run = True
|
||||||
|
self.stopped = False
|
||||||
|
self.debug = False
|
||||||
|
self._last_debug_print_ms = 0
|
||||||
|
self._wdt = WDT()
|
||||||
|
|
||||||
|
|
||||||
def sync(self):
|
def sync(self):
|
||||||
@@ -258,65 +264,6 @@ class Patterns:
|
|||||||
self.pattern_step = (self.pattern_step + 1) % 2
|
self.pattern_step = (self.pattern_step + 1) % 2
|
||||||
self.last_update = current_time
|
self.last_update = current_time
|
||||||
|
|
||||||
def random_color_wipe_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
|
||||||
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
||||||
if self.pattern_step < self.num_leds:
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
self.n[i] = (0, 0, 0)
|
|
||||||
self.n[self.pattern_step] = self.apply_brightness(color)
|
|
||||||
self.n.write()
|
|
||||||
self.pattern_step += 1
|
|
||||||
else:
|
|
||||||
self.pattern_step = 0
|
|
||||||
self.last_update = current_time
|
|
||||||
|
|
||||||
def random_rainbow_cycle_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay: # Kept original delay for now
|
|
||||||
def wheel(pos):
|
|
||||||
if pos < 85:
|
|
||||||
return (pos * 3, 255 - pos * 3, 0)
|
|
||||||
elif pos < 170:
|
|
||||||
pos -= 85
|
|
||||||
return (255 - pos * 3, 0, pos * 3)
|
|
||||||
else:
|
|
||||||
pos -= 170
|
|
||||||
return (0, pos * 3, 255 - pos * 3)
|
|
||||||
|
|
||||||
random_offset = random.randint(0, 255)
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
rc_index = (i * 256 // self.num_leds) + self.pattern_step + random_offset
|
|
||||||
self.n[i] = self.apply_brightness(wheel(rc_index & 255))
|
|
||||||
self.n.write()
|
|
||||||
self.pattern_step = (self.pattern_step + 1) % 256
|
|
||||||
self.last_update = current_time
|
|
||||||
|
|
||||||
def random_theater_chase_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay:
|
|
||||||
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
||||||
for i in range(self.num_leds):
|
|
||||||
if (i + self.pattern_step) % 3 == 0:
|
|
||||||
self.n[i] = self.apply_brightness(color)
|
|
||||||
else:
|
|
||||||
self.n[i] = (0, 0, 0)
|
|
||||||
self.n.write()
|
|
||||||
self.pattern_step = (self.pattern_step + 1) % 3
|
|
||||||
self.last_update = current_time
|
|
||||||
|
|
||||||
def random_blink_step(self):
|
|
||||||
current_time = utime.ticks_ms()
|
|
||||||
if utime.ticks_diff(current_time, self.last_update) >= self.delay*10:
|
|
||||||
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
||||||
if self.pattern_step % 2 == 0:
|
|
||||||
self.fill(self.apply_brightness(color))
|
|
||||||
else:
|
|
||||||
self.fill((0, 0, 0))
|
|
||||||
self.pattern_step = (self.pattern_step + 1) % 2
|
|
||||||
self.last_update = current_time
|
|
||||||
|
|
||||||
def color_transition_step(self):
|
def color_transition_step(self):
|
||||||
current_time = utime.ticks_ms()
|
current_time = utime.ticks_ms()
|
||||||
|
|
||||||
@@ -377,3 +324,156 @@ class Patterns:
|
|||||||
flicker_color = self.apply_brightness(base_color, brightness_override=flicker_brightness)
|
flicker_color = self.apply_brightness(base_color, brightness_override=flicker_brightness)
|
||||||
self.fill(flicker_color)
|
self.fill(flicker_color)
|
||||||
self.last_update = current_time
|
self.last_update = current_time
|
||||||
|
|
||||||
|
def radiate(self):
|
||||||
|
# Radiate pattern: creates radiating effects from multiple nodes
|
||||||
|
# n1 = distance between nodes, n2 = time for pattern to complete in ms
|
||||||
|
# Pattern repeats every self.delay milliseconds
|
||||||
|
self.run = True
|
||||||
|
last = utime.ticks_ms()
|
||||||
|
accum = 0
|
||||||
|
pattern_start = utime.ticks_ms()
|
||||||
|
step = 0
|
||||||
|
|
||||||
|
if self.delay == 0:
|
||||||
|
# Single-shot mode: run one complete cycle
|
||||||
|
delay_ms = 20 # Use 20ms for smooth animation
|
||||||
|
while self.run:
|
||||||
|
now = utime.ticks_ms()
|
||||||
|
dt = utime.ticks_diff(now, last)
|
||||||
|
if dt < 0:
|
||||||
|
dt = 0
|
||||||
|
last = now
|
||||||
|
accum += dt
|
||||||
|
|
||||||
|
if accum < delay_ms:
|
||||||
|
continue
|
||||||
|
accum = 0
|
||||||
|
step += 1
|
||||||
|
|
||||||
|
# Clear all LEDs
|
||||||
|
self.n.fill((0, 0, 0))
|
||||||
|
|
||||||
|
# Calculate pattern parameters
|
||||||
|
n1 = self.n1 if self.n1 > 0 else 10 # Distance between nodes
|
||||||
|
n3 = self.n3 if self.n3 > 0 else 500 # Time to radiate out in ms
|
||||||
|
n4 = self.n4 if self.n4 > 0 else 500 # Time to radiate in in ms
|
||||||
|
|
||||||
|
# Calculate current time within the radiate cycle (out + in)
|
||||||
|
elapsed = utime.ticks_diff(now, pattern_start)
|
||||||
|
total_cycle_time = n3 + n4 if (n3 + n4) > 0 else 1
|
||||||
|
cycle_time = elapsed % total_cycle_time
|
||||||
|
|
||||||
|
# Calculate nodes positions
|
||||||
|
nodes = []
|
||||||
|
for i in range(0, self.num_leds, n1):
|
||||||
|
nodes.append(i)
|
||||||
|
|
||||||
|
# For each node, create radiating effect
|
||||||
|
for node_pos in nodes:
|
||||||
|
max_radius = min(node_pos, self.num_leds - node_pos - 1)
|
||||||
|
if max_radius <= 0:
|
||||||
|
continue
|
||||||
|
if cycle_time <= n3 and n3 > 0:
|
||||||
|
out_progress = cycle_time / n3
|
||||||
|
wave_radius = int(out_progress * max_radius)
|
||||||
|
else:
|
||||||
|
in_time = cycle_time - n3
|
||||||
|
in_progress = (in_time / n4) if n4 > 0 else 1.0
|
||||||
|
wave_radius = int((1.0 - in_progress) * max_radius)
|
||||||
|
for radius in range(wave_radius + 1):
|
||||||
|
intensity = 1.0 - (radius / max_radius) if max_radius > 0 else 1.0
|
||||||
|
if intensity <= 0:
|
||||||
|
continue
|
||||||
|
scaled_intensity = int(self.brightness * intensity)
|
||||||
|
r = (self.colors[0][0] * scaled_intensity) // 255
|
||||||
|
g = (self.colors[0][1] * scaled_intensity) // 255
|
||||||
|
b = (self.colors[0][2] * scaled_intensity) // 255
|
||||||
|
left_pos = node_pos - radius
|
||||||
|
if left_pos >= 0:
|
||||||
|
self.n[left_pos] = (r, g, b)
|
||||||
|
right_pos = node_pos + radius
|
||||||
|
if right_pos < self.num_leds:
|
||||||
|
self.n[right_pos] = (r, g, b)
|
||||||
|
|
||||||
|
self.n.write()
|
||||||
|
self._wdt.feed()
|
||||||
|
|
||||||
|
# Single-shot: stop after one full out+in cycle
|
||||||
|
if elapsed >= total_cycle_time:
|
||||||
|
self.run = False
|
||||||
|
self.n.fill((0, 0, 0))
|
||||||
|
self.n.write()
|
||||||
|
self.stopped = True
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# Auto mode: restart wave every delay_ms
|
||||||
|
delay_ms = self.delay
|
||||||
|
while self.run:
|
||||||
|
now = utime.ticks_ms()
|
||||||
|
dt = utime.ticks_diff(now, last)
|
||||||
|
if dt < 0:
|
||||||
|
dt = 0
|
||||||
|
last = now
|
||||||
|
accum += dt
|
||||||
|
|
||||||
|
if accum < delay_ms:
|
||||||
|
continue
|
||||||
|
accum = 0
|
||||||
|
step += 1
|
||||||
|
|
||||||
|
# Clear all LEDs
|
||||||
|
self.n.fill((0, 0, 0))
|
||||||
|
|
||||||
|
# Calculate pattern parameters
|
||||||
|
n1 = self.n1 if self.n1 > 0 else 10 # Distance between nodes
|
||||||
|
n3 = self.n3 if self.n3 > 0 else 500 # Time to radiate out in ms
|
||||||
|
n4 = self.n4 if self.n4 > 0 else 500 # Time to radiate in in ms
|
||||||
|
|
||||||
|
# Calculate current time within the radiate cycle (out + in)
|
||||||
|
elapsed = utime.ticks_diff(now, pattern_start)
|
||||||
|
total_cycle_time = n3 + n4 if (n3 + n4) > 0 else 1
|
||||||
|
cycle_time = elapsed % total_cycle_time
|
||||||
|
|
||||||
|
# Calculate nodes positions
|
||||||
|
nodes = []
|
||||||
|
for i in range(0, self.num_leds, n1):
|
||||||
|
nodes.append(i)
|
||||||
|
|
||||||
|
# For each node, create radiating effect
|
||||||
|
for node_pos in nodes:
|
||||||
|
max_radius = min(node_pos, self.num_leds - node_pos - 1)
|
||||||
|
if max_radius <= 0:
|
||||||
|
continue
|
||||||
|
if cycle_time <= n3 and n3 > 0:
|
||||||
|
out_progress = cycle_time / n3
|
||||||
|
wave_radius = int(out_progress * max_radius)
|
||||||
|
else:
|
||||||
|
in_time = cycle_time - n3
|
||||||
|
in_progress = (in_time / n4) if n4 > 0 else 1.0
|
||||||
|
wave_radius = int((1.0 - in_progress) * max_radius)
|
||||||
|
for radius in range(wave_radius + 1):
|
||||||
|
intensity = 1.0 - (radius / max_radius) if max_radius > 0 else 1.0
|
||||||
|
if intensity <= 0:
|
||||||
|
continue
|
||||||
|
scaled_intensity = int(self.brightness * intensity)
|
||||||
|
r = (self.colors[0][0] * scaled_intensity) // 255
|
||||||
|
g = (self.colors[0][1] * scaled_intensity) // 255
|
||||||
|
b = (self.colors[0][2] * scaled_intensity) // 255
|
||||||
|
left_pos = node_pos - radius
|
||||||
|
if left_pos >= 0:
|
||||||
|
self.n[left_pos] = (r, g, b)
|
||||||
|
right_pos = node_pos + radius
|
||||||
|
if right_pos < self.num_leds:
|
||||||
|
self.n[right_pos] = (r, g, b)
|
||||||
|
|
||||||
|
self.n.write()
|
||||||
|
self._wdt.feed()
|
||||||
|
|
||||||
|
# Auto mode: restart the wave every delay_ms
|
||||||
|
if elapsed >= delay_ms:
|
||||||
|
if self.debug:
|
||||||
|
print("[radiate] restart cycle: delay=", delay_ms, "elapsed=", elapsed, "step=", step)
|
||||||
|
pattern_start = now
|
||||||
|
|
||||||
|
self.stopped = True
|
||||||
|
|||||||
Reference in New Issue
Block a user