from machine import Pin, I2C
import ssd1306
import time
import ds1307
# Initialize I2C on ESP32 - 21 = SDA, 22 = SCL
i2c = I2C(0, scl=Pin(22), sda = (21))
# Initialize RTC
rtc = ds1307.DS1307(i2c)
# Setting RTC to Current Time
# rtc.datetime((2025, 10, 9, 3, 15. 40, 0))
# Initialize OLED Display
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# Initialize buzzer
buzzer = Pin(15, Pin.OUT)
# Rotary Encoder
clk = Pin(32, Pin.IN, Pin.PULL_UP)
dt = Pin(33, Pin.IN, Pin.PULL_UP)
sw = Pin(25, Pin.IN, Pin.PULL_UP)
# Alarm Time
alarm_hour = 17
alarm_min = 27
edit_mode = 0 # 0 = show, 1 = edit hour, 2 = edit minute
last_clk = clk.value()
def show_time():
t = rtc.datetime()
oled.fill(0)
oled.text(f"{t[0]}-{t[1]:02d}-{t[2]:02d}", 20, 0)
oled.text(f"{t[4]:02d}:{t[5]:02d}:{t[6]:02d}", 30, 20)
# Highlight and show alarm
if edit_mode == 0:
oled.text(f"Alarm: {alarm_hour:02d}:{alarm_min:02d}", 17, 40)
elif edit_mode == 1:
oled.text(f"Alarm: [{alarm_hour:02d}]:{alarm_min:02d}", 17, 40)
elif edit_mode == 2:
oled.text(f"Alarm: {alarm_hour:02d}:[{alarm_min:02d}]", 17, 40)
oled.show()
def ring_alarm():
oled.text("ALARM", 40, 60)
oled.show()
for i in range(10):
buzzer.on()
time.sleep(0.2)
buzzer.off()
time.sleep(0.2)
def check_encoder():
global last_clk, alarm_hour, alarm_min
current_clk = clk.value()
if current_clk != last_clk:
# detect rotation direction
if dt.value() != current_clk:
delta = 1
else:
delta = -1
if edit_mode == 1:
alarm_hour = (alarm_hour + delta) % 24
elif edit_mode == 2:
alarm_min = (alarm_min + delta) % 60
last_clk = current_clk
show_time()
def check_button():
global edit_mode
if sw.value() == 0:
time.sleep(0.2)
while sw.value() == 0:
pass
edit_mode = (edit_mode + 1) % 3
show_time()
while True:
check_encoder()
check_button()
show_time()
if edit_mode == 0:
t = rtc.datetime()
if t[4] == alarm_hour and t[5] == alarm_min and t[6] == 0:
ring_alarm()
time.sleep(0.05)