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
|
||||
import utime
|
||||
import random
|
||||
@@ -19,6 +19,7 @@ class Patterns:
|
||||
"blink": self.blink_step,
|
||||
"color_transition": self.color_transition_step, # Added new pattern
|
||||
"flicker": self.flicker_step,
|
||||
"radiate": self.radiate,
|
||||
}
|
||||
self.selected = selected
|
||||
# Ensure colors list always starts with at least two for robust transition handling
|
||||
@@ -33,6 +34,17 @@ class Patterns:
|
||||
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
|
||||
|
||||
# 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):
|
||||
@@ -312,3 +324,156 @@ class Patterns:
|
||||
flicker_color = self.apply_brightness(base_color, brightness_override=flicker_brightness)
|
||||
self.fill(flicker_color)
|
||||
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