Files
led-driver/src/patterns/colour_cycle.py

101 lines
3.7 KiB
Python

import utime
from patterns.pattern_modes import style_mode
_LEGACY = {"rainbow": 1, "gradient_scroll": 0}
class ColourCycle:
def __init__(self, driver):
self.driver = driver
def _wheel(self, pos):
if pos < 85:
return (pos * 3, 255 - pos * 3, 0)
if pos < 170:
pos -= 85
return (255 - pos * 3, 0, pos * 3)
pos -= 170
return (0, pos * 3, 255 - pos * 3)
def _render_gradient(self, preset, colors, phase, brightness):
num_leds = self.driver.num_leds
color_count = len(colors)
if num_leds <= 0 or color_count <= 0:
return
if color_count == 1:
self.driver.fill(self.driver.apply_brightness(colors[0], brightness))
return
full_span = color_count * 256
phase_shift = (phase * full_span) // 256
for i in range(num_leds):
pos = ((i * full_span) // num_leds + phase_shift) % full_span
idx = pos // 256
frac = pos & 255
c1 = colors[idx]
c2 = colors[(idx + 1) % color_count]
blended = (
c1[0] + ((c2[0] - c1[0]) * frac) // 256,
c1[1] + ((c2[1] - c1[1]) * frac) // 256,
c1[2] + ((c2[2] - c1[2]) * frac) // 256,
)
self.driver.n[self.driver.led_i(preset, i)] = self.driver.apply_brightness(
blended, brightness
)
self.driver.n.write()
def _render_rainbow(self, preset, phase, brightness):
num_leds = self.driver.num_leds
for i in range(num_leds):
rc_index = (i * 256 // max(1, num_leds)) + phase
self.driver.n[self.driver.led_i(preset, i)] = self.driver.apply_brightness(
self._wheel(rc_index & 255), brightness
)
self.driver.n.write()
def run(self, preset):
"""Scroll gradient (n6=0) or fixed spectrum wheel (n6=1, legacy rainbow).
n1: step rate
n6: 0 gradient scroll, 1 rainbow wheel
"""
mode = style_mode(preset, 0, _LEGACY)
step_amount = max(1, int(preset.n1) if int(preset.n1) > 0 else 1)
phase = self.driver.step % 256
if mode == 1:
if not preset.a:
self._render_rainbow(preset, phase, preset.b)
self.driver.step = (phase + self.driver.signed(preset, step_amount)) % 256
yield
return
last_update = utime.ticks_ms()
while True:
delay_ms = max(1, int(preset.d))
now = utime.ticks_ms()
if utime.ticks_diff(now, last_update) >= delay_ms:
self._render_rainbow(preset, phase, preset.b)
phase = (phase + self.driver.signed(preset, step_amount)) % 256
self.driver.step = phase
last_update = utime.ticks_add(last_update, delay_ms)
yield
colors = preset.c if preset.c else [(255, 0, 0), (0, 0, 255)]
if not preset.a:
self._render_gradient(preset, colors, phase, preset.b)
self.driver.step = (phase + self.driver.signed(preset, step_amount)) % 256
yield
return
last_update = utime.ticks_ms()
while True:
delay_ms = max(1, int(preset.d))
now = utime.ticks_ms()
if utime.ticks_diff(now, last_update) >= delay_ms:
self._render_gradient(preset, colors, phase, preset.b)
phase = (phase + self.driver.signed(preset, step_amount)) % 256
self.driver.step = phase
last_update = utime.ticks_add(last_update, delay_ms)
yield