57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
import utime
|
|
|
|
|
|
class ColourCycle:
|
|
def __init__(self, driver):
|
|
self.driver = driver
|
|
|
|
def _render(self, 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
|
|
# Match rainbow behaviour: phase is 0..255 and maps to one full-strip shift.
|
|
phase_shift = (phase * full_span) // 256
|
|
for i in range(num_leds):
|
|
# Position around the colour loop, shifted by phase.
|
|
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[i] = self.driver.apply_brightness(blended, brightness)
|
|
self.driver.n.write()
|
|
|
|
def run(self, preset):
|
|
colors = preset.c if preset.c else [(255, 255, 255)]
|
|
phase = self.driver.step % 256
|
|
step_amount = max(1, int(preset.n1))
|
|
|
|
if not preset.a:
|
|
self._render(colors, phase, preset.b)
|
|
self.driver.step = (phase + step_amount) % 256
|
|
yield
|
|
return
|
|
|
|
last_update = utime.ticks_ms()
|
|
while True:
|
|
current_time = utime.ticks_ms()
|
|
delay_ms = max(1, int(preset.d))
|
|
if utime.ticks_diff(current_time, last_update) >= delay_ms:
|
|
self._render(colors, phase, preset.b)
|
|
phase = (phase + step_amount) % 256
|
|
self.driver.step = phase
|
|
last_update = utime.ticks_add(last_update, delay_ms)
|
|
yield
|