diff options
| author | Paul Harrison <[email protected]> | 2026-07-06 14:46:11 -0700 |
|---|---|---|
| committer | Paul Harrison <[email protected]> | 2026-07-06 14:46:11 -0700 |
| commit | f165a7b52568e83cb5099b35f7f83795ec159337 (patch) | |
| tree | 1195778c65449e1275940c177df7f9f3890b4dbb /clock.py | |
clock v1main
Diffstat (limited to 'clock.py')
| -rw-r--r-- | clock.py | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/clock.py b/clock.py new file mode 100644 index 0000000..3abe84a --- /dev/null +++ b/clock.py @@ -0,0 +1,289 @@ +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) |
