import machine import time import neopixel # ============================================================ # HEARTBEAT CLASS (smooth fading version) # ============================================================ class HeartbeatFadeNeoPixel: def __init__(self, neopixel_obj, pixel_index=0, color=(255, 0, 0), max_brightness=100, step=2, interval_ms=20): self.np = neopixel_obj self.index = pixel_index self.color = color self.max_brightness = max_brightness self.step = step # how fast brightness changes self.interval = interval_ms self.brightness = 0 self.direction = 1 # 1 = going up, -1 = going down self.last_time = time.ticks_ms() def apply_brightness(self, c, level): r, g, b = c factor = level / 100 return (int(r * factor), int(g * factor), int(b * factor)) def update(self): now = time.ticks_ms() if time.ticks_diff(now, self.last_time) >= self.interval: self.last_time = now # Update brightness self.brightness += self.direction * self.step # Bounce at limits if self.brightness >= self.max_brightness: self.brightness = self.max_brightness self.direction = -1 if self.brightness <= 0: self.brightness = 0 self.direction = 1 # Apply brightness self.np[self.index] = self.apply_brightness(self.color, self.brightness) self.np.write() # ============================================================ # NEOPIXEL SETUP # ============================================================ # 3-LED strip on GP17 STRIP_PIN = 17 STRIP_LEDS = 3 strip = neopixel.NeoPixel(machine.Pin(STRIP_PIN), STRIP_LEDS) # Single heartbeat pixel on GP28 SINGLE_PIN = 28 single = neopixel.NeoPixel(machine.Pin(SINGLE_PIN), 1) # ============================================================ # BUTTONS (GP20, GP21, GP22) # ============================================================ button_pins = [20, 21, 22] buttons = [machine.Pin(pin, machine.Pin.IN, machine.Pin.PULL_UP) for pin in button_pins] # ============================================================ # COLOR PALETTE # ============================================================ colors = [ (0, 0, 0), # Off (255, 0, 0), # Red (0, 255, 0), # Green (0, 0, 255), # Blue (255, 255, 0), # Yellow (0, 255, 255), # Cyan (255, 0, 255), # Magenta (255, 128, 0), # Orange (128, 0, 255), # Purple (255, 20, 147), # Pink (128, 255, 0), # Lime (255, 255, 255), # White ] # ============================================================ # STATE FOR PIXELS 0–2 (BUTTON-CONTROLLED) # ============================================================ color_index = [0, 0, 0] brightness = [50, 50, 50] last_state = [1, 1, 1] press_time = [0, 0, 0] # ============================================================ # HEARTBEAT PIXEL CONFIG (smooth fade) # ============================================================ FLASH_COLOR_INDEX = 1 # Choose from palette FLASH_MAX_BRIGHTNESS = 20 # Peak brightness for fade FLASH_STEP = 0.5 # Speed of fade FLASH_INTERVAL_MS = 30 # Lower = smoother animation heartbeat = HeartbeatFadeNeoPixel( neopixel_obj=single, pixel_index=0, color=colors[FLASH_COLOR_INDEX], max_brightness=FLASH_MAX_BRIGHTNESS, step=FLASH_STEP, interval_ms=FLASH_INTERVAL_MS ) # ============================================================ # HELPERS # ============================================================ def apply_brightness(color, level): r, g, b = color factor = level / 100 return (int(r * factor), int(g * factor), int(b * factor)) def update_strip(): for i in range(STRIP_LEDS): strip[i] = apply_brightness(colors[color_index[i]], brightness[i]) strip.write() # ============================================================ # INITIAL STATE # ============================================================ update_strip() # ============================================================ # MAIN LOOP # ============================================================ while True: now = time.ticks_ms() # -------------------------------- # BUTTON HANDLING FOR 3-LED STRIP # -------------------------------- for i in range(3): state = buttons[i].value() if last_state[i] == 1 and state == 0: press_time[i] = now if last_state[i] == 0 and state == 1: duration = time.ticks_diff(now, press_time[i]) if duration > 500: brightness[i] += 10 if brightness[i] > 100: brightness[i] = 10 else: color_index[i] = (color_index[i] + 1) % len(colors) update_strip() time.sleep_ms(200) last_state[i] = state # ---------------------------- # SMOOTH HEARTBEAT UPDATE # ---------------------------- heartbeat.update() time.sleep_ms(10)