Add simplified radiate pattern to dev branch
- Add radiate pattern to patterns dictionary - Implement clean radiate function with single-shot and auto modes - Add WDT import and radiate-specific attributes - Single wave at a time in auto mode (no overlapping complexity) - Simple debug output for restart timing - Maintains same functionality with cleaner implementation
This commit is contained in:
167
src/patterns.py
167
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
|
||||||
@@ -19,6 +19,7 @@ class Patterns:
|
|||||||
"blink": self.blink_step,
|
"blink": self.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,
|
||||||
|
"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
|
||||||
@@ -34,6 +35,17 @@ class Patterns:
|
|||||||
|
|
||||||
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):
|
||||||
self.pattern_step=0
|
self.pattern_step=0
|
||||||
@@ -312,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