import machine import neopixel import utime import urandom from i2c_handler import I2CSlaveHandler, Packet class LedHandler(I2CSlaveHandler): def __init__(self, i2c_id, sda, scl, slave_addr): super().__init__(i2c_id, sda, scl, slave_addr) self.np = neopixel.NeoPixel(machine.Pin(29), 20) self.mode = 2 # Start im rainbow mode self.std_index = 0 self.rainbow_index = 0 self.rainbow_colors = self.generate_rainbow_colors(18 * 2) # doppelte Länge self.rot_index = 0 self.rot_dir = 1 # Richtung für Puls self.flashing_state = [0] * 20 # Status je LED self.last_update = utime.ticks_ms() def hsv_to_rgb(self, h, s, v): h = float(h) s = float(s) v = float(v) if s == 0.0: return (int(v * 255), int(v * 255), int(v * 255)) i = int(h * 6) f = (h * 6) - i p = v * (1 - s) q = v * (1 - s * f) t = v * (1 - s * (1 - f)) i = i % 6 if i == 0: r, g, b = v, t, p elif i == 1: r, g, b = q, v, p elif i == 2: r, g, b = p, v, t elif i == 3: r, g, b = p, q, v elif i == 4: r, g, b = t, p, v elif i == 5: r, g, b = v, p, q return (int(r * 255), int(g * 255), int(b * 255)) def update(self): now = utime.ticks_ms() if self.mode == 1: # rot if utime.ticks_diff(now, self.last_update) >= 30: self.rot_step() self.last_update = now elif self.mode == 2: # rainbow if utime.ticks_diff(now, self.last_update) >= 100: self.rainbow_step() self.last_update = now elif self.mode == 3: # standard if utime.ticks_diff(now, self.last_update) >= 100: self.standard_step() self.last_update = now elif self.mode == 4: # flashing if utime.ticks_diff(now, self.last_update) >= 50: self.flashing_step() self.last_update = now super().update() def process_packet(self, packet: Packet): cmd = packet[0] if cmd == 0x10: self.mode = packet[2] print(f"Set colormode to {self.mode}") else: print(f"Unknown command 0x{cmd:02X}") self.response_packet = None # 🔴 Nicht-blockierende ROT-Animation (Pulsieren) def rot_step(self): brightness = self.rot_index color = (brightness, 0, 0) self.np.fill(color) self.np.write() self.rot_index += self.rot_dir * 5 if self.rot_index >= 255: self.rot_index = 255 self.rot_dir = -1 elif self.rot_index <= 0: self.rot_index = 0 self.rot_dir = 1 # 🌈 Verbesserter Regenbogen mit mehr Farben def rainbow_step(self): for i in range(18): color_index = (self.rainbow_index + i) % len(self.rainbow_colors) self.np[i] = self.rainbow_colors[color_index] self.np[18] = (0, 0, 0) self.np[19] = (0, 0, 0) self.np.write() self.rainbow_index = (self.rainbow_index + 1) % len(self.rainbow_colors) def generate_rainbow_colors(self, steps): colors = [] for i in range(steps): hue = i / steps # 0.0 - 1.0 → 0° - 360° rgb = self.hsv_to_rgb(hue, 1.0, 1.0) colors.append(rgb) return colors # 🔵 Standard-Lauflicht def standard_step(self): i = self.std_index self.np[i % 17] = (0, 0, 225) if i >= 4: self.np[i - 4] = (0, 225, 100) if i >= 8: self.np[i - 8] = (0, 225, 0) if i >= 12: self.np[i - 12] = (0, 225, 100) self.np[17] = (0, 0, 255) self.np[18] = (0, 0, 255) self.np.write() self.std_index = (i + 1) % 17 # ✨ Flashing-Effekt mit zufälligen LEDs def flashing_step(self): for i in range(20): if self.flashing_state[i] > 0: self.flashing_state[i] -= 1 if self.flashing_state[i] == 0: self.np[i] = (0, 0, 0) elif urandom.getrandbits(6) == 0: # ca. 1:64 Chance zu flashen self.flashing_state[i] = urandom.getrandbits(2) + 1 color = urandom.choice([ (255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255), (255, 0, 255) ]) self.np[i] = color self.np.write() def main(): handler = LedHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x42) print("LED handler I2C slave started") try: handler.handle() except KeyboardInterrupt: handler.deinit() print("I2C slave stopped") if __name__ == "__main__": main()