from machine import RTC, Pin, Timer import time in_setup_menu = False class Alarm: def __init__(self): self.enabled = False self.time = [0, 0, 0] self.snoozed = False self.snooze_duration = 5 self.snooze_end_time = [0, 0, 0] def toggle(self): self.enabled = not self.enabled def going_off(self): now = RTC.datetime() now_secs = (now[3] * 60 + now[4]) * 60 + now[5] target_secs = (self.time[0] * 60 + self.now[1]) * 60 + self.now[2] if now_secs >= target_secs: pass def snooze(self): if self.going_off(): self.snoozed = True self.snooze_end_time[1] += self.snooze_duration class Editor: def __init__(self): self.begin() self.active = False def begin(self): now = rtc.datetime() self.selection = 0 self.units = [now[4], now[5], now[6]] self.active = True def increment_selected(self, n=1): t = self.get_selection() + n if (self.selection == 0 and t >= 24) or t >= 60: t = 0 self.set_selection(t) def decrement_selected(self, n=1): t = self.get_selection() - n if t < 0: if self.selection == 0: t = 23 else: t = 59 self.set_selection(t) def select_next(self): self.selection += 1 if self.selection > 2: self.selection = 0 def set_selection(self, t): self.units[self.selection] = t def get_selection(self): return self.units[self.selection] def finish(self): now = rtc.datetime() newtime = (now[0], now[1], now[2], now[3], self.units[0], self.units[1], self.units[2], 0) rtc.datetime(newtime) print(now, newtime, rtc.datetime()) self.active = False def __str__(self): return f"{self.units[0]:02d}:{self.units[1]:02d}:{self.units[2]:02d}" def get_cursor_position(self): if self.selection == 0: return 0 elif self.selection == 1: return 3 elif self.selection == 2: return 6 class Display: def __init__(self, rs, e, d4, d5, d6, d7): self.rs_pin = Pin(rs, Pin.OUT) self.e_pin = Pin(e, Pin.OUT) self.data_pins = list(map(lambda p: Pin(p, Pin.OUT), [d4, d5, d6, d7])) self.cursor_state = False # init sequence time.sleep_ms(20) self.command_nibble(0x03) self.command_nibble(0x03) self.command_nibble(0x03) self.command_nibble(0x02) self.command(0x28) self.command(0x01) self.command(0x06) self.command(0x0C) def set_nibble(self, data): for i in range(4): bit = data & 1 data >>= 1 self.data_pins[i].value(bit) def command_nibble(self, cmd): self.set_nibble(cmd) self.rs_pin.off() self.e_pin.on() time.sleep_ms(1) self.e_pin.off() time.sleep_ms(2) def command(self, cmd): self.command_nibble((cmd >> 4) & 0x0F) self.command_nibble(cmd & 0x0F) def write_char(self, c): self.set_nibble((c >> 4) & 0x0F) self.rs_pin.on() self.e_pin.on() time.sleep_ms(1) self.e_pin.off() self.set_nibble(c & 0x0F) self.e_pin.on() time.sleep_ms(1) self.e_pin.off() time.sleep_ms(1) def write(self, msg): s = self.cursor_state if s: self.cursor_off() self.set_cursor_position(0) for c in msg: self.write_char(ord(c)) if s: self.cursor_on() def set_cursor_position(self, pos): self.command(0x80 | pos) def cursor_on(self): self.cursor_state = True self.command(0x0E) def cursor_off(self): self.cursor_state = False self.command(0x0C) def setup_menu(p): redraw = True incdec_time = None incdec_count = 0 setup_button_down = True editor.begin() display.cursor_on() while True: if redraw: display.write(str(editor)) display.set_cursor_position(editor.get_cursor_position()) redraw = False while setup_button_down: if not setup_state: setup_button_down = False # increment / decrement if incdec_time is None: if increase_state or decrease_state: incdec_time = time.ticks_ms() - 500 else: if not increase_state and not decrease_state: incdec_time = None incdec_count = 0 elif time.ticks_diff(time.ticks_ms(), incdec_time) >= (500 if incdec_count < 4 else 250): incdec_time = time.ticks_ms() incdec_count += 1 if increase_state: editor.increment_selected() else: editor.decrement_selected() redraw = True # select next button if setup_state: setup_button_down = True editor.select_next() redraw = True time.sleep_ms(100) # snooze / finish button if snooze_state: break display.cursor_off() editor.finish() def toggle_alarm(p): pass def display_time(): now = rtc.datetime() display.write(f"{now[4]:02d}:{now[5]:02d}:{now[6]:02d}") increase_state = False decrease_state = False snooze_state = False alarm_state = False setup_state = False # debounce counters increase_count = 0 decrease_count = 0 snooze_count = 0 alarm_count = 0 setup_count = 0 DEBOUNCE_SAMPLES = 5 def debounce(pin, state, count): pressed = (pin.value() == 0) # active low if pressed == state: count = 0 else: count += 1 if count >= DEBOUNCE_SAMPLES: state = pressed count = 0 return state, count def timer_callback(timer): global increase_state, decrease_state global snooze_state, alarm_state global increase_count, decrease_count global snooze_count, alarm_count global setup_count, setup_state increase_state, increase_count = debounce( increase_btn, increase_state, increase_count ) decrease_state, decrease_count = debounce( decrease_btn, decrease_state, decrease_count ) snooze_state, snooze_count = debounce( snooze_btn, snooze_state, snooze_count ) alarm_state, alarm_count = debounce( alarm_btn, alarm_state, alarm_count ) setup_state, setup_count = debounce( setup_btn, setup_state, setup_count ) rtc = RTC() editor = Editor() display = Display(29, 27, 10, 11, 12, 13) setup_btn = Pin(17, Pin.IN, Pin.PULL_UP) alarm_btn = Pin(20, Pin.IN, Pin.PULL_UP) snooze_btn = Pin(26, Pin.IN, Pin.PULL_UP) increase_btn = Pin(28, Pin.IN, Pin.PULL_UP) decrease_btn = Pin(23, Pin.IN, Pin.PULL_UP) tim = Timer(period=10, mode=Timer.PERIODIC, callback=timer_callback) #setup_btn.irq(handler=setup_menu) #setup_btn.irq(handler=lambda p: print("setup")) #alarm_btn.irq(handler=lambda p: print("alarm_btn")) #snooze_btn.irq(handler=lambda p: print("snooze_btn")) #increase_btn.irq(handler=lambda p: print("increase_btn")) #decrease_btn.irq(handler=lambda p: print("decrease_btn")) while True: #print(setup_state, increase_state, decrease_state, snooze_state) if setup_state: setup_menu(None) display_time() time.sleep_ms(10)