summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Harrison <[email protected]>2026-07-06 14:46:11 -0700
committerPaul Harrison <[email protected]>2026-07-06 14:46:11 -0700
commitf165a7b52568e83cb5099b35f7f83795ec159337 (patch)
tree1195778c65449e1275940c177df7f9f3890b4dbb
clock v1main
-rw-r--r--clock.py289
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)