This commit is contained in:
Aaro Varis
2026-02-05 09:09:23 +02:00
parent f553bc7877
commit 26da910850

75
init.py
View File

@@ -1,8 +1,9 @@
from time import time
from astral import LocationInfo
from astral.sun import sun
from datetime import date, datetime
from datetime import date, datetime, timedelta
from zoneinfo import ZoneInfo
from typing import Callable
import requests
from grove.gpio import GPIO
@@ -48,8 +49,20 @@ def isSunUp() -> bool:
now = datetime.now(city.tzinfo)
return s["sunrise"] <= now <= s["sunset"]
class WakeUpAction:
offsetSeconds: int # how many seconds before alarm time to trigger
action: Callable[[], None]
triggered: bool = False
def __init__(self, offsetSeconds: int, action: Callable[[], None]):
self.offsetSeconds = offsetSeconds
self.action = action
self.triggered = False
# sunset and sunrise
class AlarmClock:
wakeupActions: list[WakeUpAction] = []
ledGpio: GPIO
buttonGpio: GPIO
relayGpio: GPIO
@@ -61,15 +74,43 @@ class AlarmClock:
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
alarmTime: datetime = datetime.now(ZoneInfo("Europe/Helsinki")).replace(hour=9, minute=13, second=0, microsecond=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.wakeupActions = []
self.setLcdText("AlarmClock Init")
def addWakeUpAction(self, offsetSeconds: int, action: Callable[[], None]):
"""Add a wakeup action to be triggered offsetSeconds before alarm time"""
self.wakeupActions.append(WakeUpAction(offsetSeconds, action))
def resetWakeUpActions(self):
"""Reset all wakeup actions so they can trigger again tomorrow"""
for action in self.wakeupActions:
action.triggered = False
def checkWakeUpActions(self):
"""Check and trigger any wakeup actions that are due"""
now = datetime.now(ZoneInfo(city.timezone))
today_alarm = now.replace(
hour=self.alarmTime.hour,
minute=self.alarmTime.minute,
second=0,
microsecond=0
)
for wakeupAction in self.wakeupActions:
if wakeupAction.triggered:
continue
trigger_time = today_alarm - timedelta(seconds=wakeupAction.offsetSeconds)
if now >= trigger_time and now < today_alarm + timedelta(minutes=1):
print(f"Triggering wakeup action (offset: {wakeupAction.offsetSeconds}s)")
wakeupAction.action()
wakeupAction.triggered = True
def start(self):
print("AlarmClock started")
@@ -88,7 +129,10 @@ class AlarmClock:
currentHour = datetime.now(ZoneInfo(city.timezone)).hour
currrentSecond = datetime.now(ZoneInfo(city.timezone)).second
self.setLcdText(f"Time {currentHour:02d}:{currentMinute:02d}:{currrentSecond:02d}\nAlarm {self.alarmHour:02d}:{self.alarmMinute:02d}")
self.setLcdText(f"Time {currentHour:02d}:{currentMinute:02d}:{currrentSecond:02d}\nAlarm {self.alarmTime.hour:02d}:{self.alarmTime.minute:02d}")
# Check and trigger wakeup actions
self.checkWakeUpActions()
# Only process button state change if debounce delay has passed
if currentButtonState != self.lastKnownButtonState:
@@ -128,27 +172,27 @@ class AlarmClock:
setShellyPlugState(shelly_deviceId, self.relayGpio.read() == 0)
elif self.configMode == "set_hour":
# Increment hour
self.alarmHour = (self.alarmHour + 1) % 24
self.setLcdText(f"Set Hour: {self.alarmHour:02d}")
self.alarmTime = self.alarmTime.replace(hour=(self.alarmTime.hour + 1) % 24)
self.setLcdText(f"Set Hour: {self.alarmTime.hour:02d}")
elif self.configMode == "set_minute":
# Increment minute
self.alarmMinute = (self.alarmMinute + 1) % 60
self.setLcdText(f"Set Min: {self.alarmMinute:02d}")
self.alarmTime = self.alarmTime.replace(minute=(self.alarmTime.minute + 1) % 60)
self.setLcdText(f"Set Min: {self.alarmTime.minute: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}")
self.setLcdText(f"Set Hour: {self.alarmTime.hour:02d}")
print(f"Entering hour setting mode")
elif self.configMode == "set_hour":
self.configMode = "set_minute"
self.setLcdText(f"Set Min: {self.alarmMinute:02d}")
self.setLcdText(f"Set Min: {self.alarmTime.minute: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}")
self.setLcdText(f"Saved: {self.alarmTime.hour:02d}:{self.alarmTime.minute:02d}")
print(f"Alarm time saved: {self.alarmTime.hour:02d}:{self.alarmTime.minute:02d}")
lastLcdText: str = ""
def setLcdText(self, text: str):
@@ -176,6 +220,13 @@ pins = {
"buzzer": 12,
}
alarm_clock = AlarmClock(pins)
# Add wakeup actions (offsetSeconds = seconds before alarm to trigger)
alarm_clock.addWakeUpAction(120, lambda: print("2 minutes to alarm!")) # 2 minutes before alarm
alarm_clock.addWakeUpAction(90, lambda: setShellyPlugState(shelly_deviceId, True)) # activate plug 90s before alarm
alarm_clock.addWakeUpAction(30, lambda: print("30 seconds to alarm!")) # 30 seconds before alarm
alarm_clock.addWakeUpAction(0, lambda: print("Alarm triggered!")) # At alarm time
alarm_clock.start()