import time from machine import Pin class Button: """A debounced button handler supporting click and long press callbacks using Pin IRQ.""" def __init__(self, pin_num, name="Button", debounce_ms=50, long_press_ms=800): self.pin = Pin(pin_num, Pin.IN, Pin.PULL_UP) self.name = name self.debounce_ms = debounce_ms self.long_press_ms = long_press_ms self.last_state = 1 # Normal high (pull-up) self.press_time = 0 self.last_debounce_time = 0 self.click_callback = None self.long_press_callback = None # Setup soft IRQ (default) to allow memory allocation and callbacks inside handler self.pin.irq(handler=self._handle_irq, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING) def is_pressed(self): """Returns True if the button is currently pressed (active low).""" return self.pin.value() == 0 def on_click(self, callback): """Register a callback function for a single click event.""" self.click_callback = callback return callback def on_long_press(self, callback): """Register a callback function for a long press event.""" self.long_press_callback = callback return callback def _handle_irq(self, pin): now = time.ticks_ms() val = pin.value() # Debounce: filter out fast state jitter if time.ticks_diff(now, self.last_debounce_time) < self.debounce_ms: return if val != self.last_state: self.last_debounce_time = now self.last_state = val if val == 0: # Button pressed self.press_time = now else: # Button released if self.press_time > 0: duration = time.ticks_diff(now, self.press_time) self.press_time = 0 # Reset if duration >= self.long_press_ms: if self.long_press_callback: self.long_press_callback() else: if self.click_callback: self.click_callback() class BoardButtons: """Convenience class containing both the BOOT (Pin 0) and KEY (Pin 18) buttons.""" def __init__(self): self.boot = Button(0, "BOOT") self.key = Button(18, "KEY")