from time import time from astral import LocationInfo from astral.sun import sun from datetime import date from grove.gpio import GPIO from grove.display.jhd1802 import JHD1802 city = LocationInfo("Seinäjoki", "Finland", "Europe/Helsinki", 62.7900, 22.8400) s = sun(city.observer, date=date.today()) print(f"City: {city.name}, {city.region}") print(f"Timezone: {city.timezone}") print(f"Latitude: {city.latitude:.6f}; Longitude: {city.longitude:.6f}") def isSunUp() -> bool: from datetime import datetime now = datetime.now(city.tzinfo) return s["sunrise"] <= now <= s["sunset"] # sunset and sunrise class AlarmClock: ledGpio: GPIO buttonGpio: GPIO relayGpio: GPIO lastKnownButtonState: bool = False lcd: JHD1802 lastButtonPressTime: float = 0.0 lastButtonStateChangeTime: float = 0.0 debounceDelay: float = 0.05 # 50ms debounce delay longPressThreshold: float = 1.0 # 1 second for long press buttonPressStartTime: float = 0.0 configMode: str = "normal" # modes: normal, set_hour, set_minute alarmHour: int = 7 alarmMinute: int = 0 def __init__(self, pins: dict = {}): self.ledGpio = GPIO(pins.get("led", 5), GPIO.OUT) self.buttonGpio = GPIO(pins.get("button", 6), GPIO.IN) self.relayGpio = GPIO(pins.get("relay", 16), GPIO.OUT) self.lcd = JHD1802() self.setLcdText("AlarmClock Init") def start(self): print("AlarmClock started") while True: self.loop() def setRelayState(self, state: bool): self.relayGpio.write(1 if state else 0) def loop(self): currentButtonState = not self.buttonGpio.read() currentTime = time() if (self.configMode == "normal"): currentMinute = int((currentTime / 60) % 60) currentHour = int((currentTime / 3600) % 24) currrentSecond = int(currentTime % 60) self.setLcdText(f"Time {currentHour:02d}:{currentMinute:02d}:{currrentSecond:02d}\nAlarm {self.alarmHour:02d}:{self.alarmMinute:02d}") # Only process button state change if debounce delay has passed if currentButtonState != self.lastKnownButtonState: if (currentTime - self.lastButtonStateChangeTime) >= self.debounceDelay: self.lastKnownButtonState = currentButtonState self.lastButtonStateChangeTime = currentTime self.onButtonPress("button", currentButtonState) # Check for long press while button is held if currentButtonState and self.buttonPressStartTime > 0: pressDuration = currentTime - self.buttonPressStartTime if pressDuration >= self.longPressThreshold: self.onLongPress() self.buttonPressStartTime = 0.0 # Reset to prevent repeated triggers def onButtonPress(self, button: str, state: bool): print(f"Button '{button}' pressed state: {state}") currentTime = time() if button == "button": if state: # Button pressed down self.buttonPressStartTime = currentTime else: # Button released if self.buttonPressStartTime > 0: pressDuration = currentTime - self.buttonPressStartTime self.buttonPressStartTime = 0.0 # Only handle as short press if it wasn't a long press if pressDuration < self.longPressThreshold: self.onShortPress() def onShortPress(self): """Handle short button press based on current mode""" if self.configMode == "normal": # Normal mode: toggle relay self.setRelayState(not self.relayGpio.read()) elif self.configMode == "set_hour": # Increment hour self.alarmHour = (self.alarmHour + 1) % 24 self.setLcdText(f"Set Hour: {self.alarmHour:02d}") elif self.configMode == "set_minute": # Increment minute self.alarmMinute = (self.alarmMinute + 1) % 60 self.setLcdText(f"Set Min: {self.alarmMinute:02d}") def onLongPress(self): """Handle long button press - cycle through configuration modes""" if self.configMode == "normal": self.configMode = "set_hour" self.setLcdText(f"Set Hour: {self.alarmHour:02d}") print(f"Entering hour setting mode") elif self.configMode == "set_hour": self.configMode = "set_minute" self.setLcdText(f"Set Min: {self.alarmMinute:02d}") print(f"Switching to minute setting mode") elif self.configMode == "set_minute": self.configMode = "normal" self.setLcdText(f"Saved: {self.alarmHour:02d}:{self.alarmMinute:02d}") print(f"Alarm time saved: {self.alarmHour:02d}:{self.alarmMinute:02d}") lastLcdText: str = "" def setLcdText(self, text: str): if text == self.lastLcdText: return self.lastLcdText = text self.lcd.clear() rows = text.split("\n") for i, row in enumerate(rows): if i == 0: self.lcd.setCursor(0, 0) self.lcd.write(f"{(" "+row):<17}") elif i == 1: self.lcd.setCursor(1, 0) self.lcd.write(row) #print(f"LCD: {text}") pins = { "button": 6, "led": 5, "buzzer": 12, } alarm_clock = AlarmClock(pins) alarm_clock.start()