diff --git a/src/patterns.py b/src/patterns.py new file mode 100644 index 0000000..58de83d --- /dev/null +++ b/src/patterns.py @@ -0,0 +1,291 @@ +from machine import Pin +from neopixel import NeoPixel +import utime +import random + +class Patterns: + def __init__(self, pin, num_leds, color1=(0,0,0), color2=(0,0,0), brightness=127, selected="rainbow_cycle", delay=100): + self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds) + self.num_leds = num_leds + self.pattern_step = 0 + self.last_update = utime.ticks_ms() + self.delay = delay + self.brightness = brightness + self.patterns = { + "off": self.off, + "on" : self.on, + "color_wipe": self.color_wipe_step, + "rainbow_cycle": self.rainbow_cycle_step, + "theater_chase": self.theater_chase_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, + "external": None + } + self.selected = selected + self.color1 = color1 + self.color2 = color2 + self.transition_duration = 50 # Duration of color transition in milliseconds + self.transition_step = 0 + + def sync(self): + self.pattern_step=0 + self.last_update = utime.ticks_ms() + + def tick(self): + if self.patterns[self.selected]: + self.patterns[self.selected]() + + def update_num_leds(self, pin, num_leds): + self.n = NeoPixel(Pin(pin, Pin.OUT), num_leds) + self.num_leds = num_leds + self.pattern_step = 0 + + def set_delay(self, delay): + self.delay = delay + + def set_brightness(self, brightness): + self.brightness = brightness + + def set_color1(self, color): + print(color) + self.color1 = self.apply_brightness(color) + + def set_color2(self, color): + self.color2 = self.apply_brightness(color) + + def apply_brightness(self, color): + return tuple(int(c * self.brightness / 255) for c in color) + + def select(self, pattern): + if pattern in self.patterns: + self.selected = pattern + return True + return False + + def set(self, i, color): + self.n[i] = color + + def write(self): + self.n.write() + + def fill(self): + for i in range(self.num_leds): + self.n[i] = self.color1 + self.n.write() + + def off(self): + color = self.color1 + self.color1 = (0,0,0) + self.fill() + self.color1 = color + + def on(self): + color = self.color1 + self.color1 = self.apply_brightness(self.color1) + self.fill() + self.color1 = color + + + def color_wipe_step(self): + color = self.apply_brightness(self.color1) + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay: + 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 rainbow_cycle_step(self): + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay/5: + 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) + + for i in range(self.num_leds): + rc_index = (i * 256 // self.num_leds) + self.pattern_step + 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 theater_chase_step(self): + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay: + for i in range(self.num_leds): + if (i + self.pattern_step) % 3 == 0: + self.n[i] = self.apply_brightness(self.color1) + else: + self.n[i] = (0, 0, 0) + self.n.write() + self.pattern_step = (self.pattern_step + 1) % 3 + self.last_update = current_time + + def blink_step(self): + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay: + if self.pattern_step % 2 == 0: + for i in range(self.num_leds): + self.n[i] = self.apply_brightness(self.color1) + else: + for i in range(self.num_leds): + self.n[i] = (0, 0, 0) + self.n.write() + self.pattern_step = (self.pattern_step + 1) % 2 + 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: + 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: + color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + if self.pattern_step % 2 == 0: + for i in range(self.num_leds): + self.n[i] = self.apply_brightness(color) + else: + for i in range(self.num_leds): + self.n[i] = (0, 0, 0) + self.n.write() + self.pattern_step = (self.pattern_step + 1) % 2 + self.last_update = current_time + + def color_transition_step(self): + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay: + # Calculate transition factor based on elapsed time + transition_factor = (self.pattern_step * 100) / self.transition_duration + if transition_factor > 100: + transition_factor = 100 + color = self.interpolate_color(self.color1, self.color2, transition_factor / 100) + + # Apply the interpolated color to all LEDs + for i in range(self.num_leds): + self.n[i] = self.apply_brightness(color) + self.n.write() + + self.pattern_step += self.delay + if self.pattern_step > self.transition_duration: + self.pattern_step = 0 + + self.last_update = current_time + + def interpolate_color(self, color1, color2, factor): + return ( + int(color1[0] + (color2[0] - color1[0]) * factor), + int(color1[1] + (color2[1] - color1[1]) * factor), + int(color1[2] + (color2[2] - color1[2]) * factor) + ) + + def two_steps_forward_one_step_back_step(self): + current_time = utime.ticks_ms() + if utime.ticks_diff(current_time, self.last_update) >= self.delay: + # Move forward 2 steps and backward 1 step + if self.direction == 1: # Moving forward + if self.scanner_position < self.num_leds - 2: + self.scanner_position += 2 # Move forward 2 steps + else: + self.direction = -1 # Change direction to backward + else: # Moving backward + if self.scanner_position > 0: + self.scanner_position -= 1 # Move backward 1 step + else: + self.direction = 1 # Change direction to forward + + # Set all LEDs to off + for i in range(self.num_leds): + self.n[i] = (0, 0, 0) + + # Set the current position to the color + self.n[self.scanner_position] = self.apply_brightness(self.color1) + + # Apply the color transition + transition_factor = (self.pattern_step * 100) / self.transition_duration + if transition_factor > 100: + transition_factor = 100 + color = self.interpolate_color(self.color1, self.color2, transition_factor / 100) + self.n[self.scanner_position] = self.apply_brightness(color) + + self.n.write() + self.pattern_step += self.delay + if self.pattern_step > self.transition_duration: + self.pattern_step = 0 + + self.last_update = current_time + +if __name__ == "__main__": + p = Patterns(4, 180) + p.set_color1((255,0,0)) + p.set_color2((0,255,0)) + #p.set_delay(10) + try: + while True: + for key in p.patterns: + print(key) + p.select(key) + for _ in range(2000): + p.tick() + utime.sleep_ms(1) + except KeyboardInterrupt: + p.fill((0, 0, 0))