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 time import time
from astral import LocationInfo from astral import LocationInfo
from astral.sun import sun from astral.sun import sun
from datetime import date, datetime from datetime import date, datetime, timedelta
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from typing import Callable
import requests import requests
from grove.gpio import GPIO from grove.gpio import GPIO
@@ -48,8 +49,20 @@ def isSunUp() -> bool:
now = datetime.now(city.tzinfo) now = datetime.now(city.tzinfo)
return s["sunrise"] <= now <= s["sunset"] 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 # sunset and sunrise
class AlarmClock: class AlarmClock:
wakeupActions: list[WakeUpAction] = []
ledGpio: GPIO ledGpio: GPIO
buttonGpio: GPIO buttonGpio: GPIO
relayGpio: GPIO relayGpio: GPIO
@@ -61,15 +74,43 @@ class AlarmClock:
longPressThreshold: float = 1.0 # 1 second for long press longPressThreshold: float = 1.0 # 1 second for long press
buttonPressStartTime: float = 0.0 buttonPressStartTime: float = 0.0
configMode: str = "normal" # modes: normal, set_hour, set_minute configMode: str = "normal" # modes: normal, set_hour, set_minute
alarmHour: int = 7 alarmTime: datetime = datetime.now(ZoneInfo("Europe/Helsinki")).replace(hour=9, minute=13, second=0, microsecond=0)
alarmMinute: int = 0
def __init__(self, pins: dict = {}): def __init__(self, pins: dict = {}):
self.ledGpio = GPIO(pins.get("led", 5), GPIO.OUT) self.ledGpio = GPIO(pins.get("led", 5), GPIO.OUT)
self.buttonGpio = GPIO(pins.get("button", 6), GPIO.IN) self.buttonGpio = GPIO(pins.get("button", 6), GPIO.IN)
self.relayGpio = GPIO(pins.get("relay", 16), GPIO.OUT) self.relayGpio = GPIO(pins.get("relay", 16), GPIO.OUT)
self.lcd = JHD1802() self.lcd = JHD1802()
self.wakeupActions = []
self.setLcdText("AlarmClock Init") 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): def start(self):
print("AlarmClock started") print("AlarmClock started")
@@ -88,7 +129,10 @@ class AlarmClock:
currentHour = datetime.now(ZoneInfo(city.timezone)).hour currentHour = datetime.now(ZoneInfo(city.timezone)).hour
currrentSecond = datetime.now(ZoneInfo(city.timezone)).second 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 # Only process button state change if debounce delay has passed
if currentButtonState != self.lastKnownButtonState: if currentButtonState != self.lastKnownButtonState:
@@ -128,27 +172,27 @@ class AlarmClock:
setShellyPlugState(shelly_deviceId, self.relayGpio.read() == 0) setShellyPlugState(shelly_deviceId, self.relayGpio.read() == 0)
elif self.configMode == "set_hour": elif self.configMode == "set_hour":
# Increment hour # Increment hour
self.alarmHour = (self.alarmHour + 1) % 24 self.alarmTime = self.alarmTime.replace(hour=(self.alarmTime.hour + 1) % 24)
self.setLcdText(f"Set Hour: {self.alarmHour:02d}") self.setLcdText(f"Set Hour: {self.alarmTime.hour:02d}")
elif self.configMode == "set_minute": elif self.configMode == "set_minute":
# Increment minute # Increment minute
self.alarmMinute = (self.alarmMinute + 1) % 60 self.alarmTime = self.alarmTime.replace(minute=(self.alarmTime.minute + 1) % 60)
self.setLcdText(f"Set Min: {self.alarmMinute:02d}") self.setLcdText(f"Set Min: {self.alarmTime.minute:02d}")
def onLongPress(self): def onLongPress(self):
"""Handle long button press - cycle through configuration modes""" """Handle long button press - cycle through configuration modes"""
if self.configMode == "normal": if self.configMode == "normal":
self.configMode = "set_hour" 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") print(f"Entering hour setting mode")
elif self.configMode == "set_hour": elif self.configMode == "set_hour":
self.configMode = "set_minute" 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") print(f"Switching to minute setting mode")
elif self.configMode == "set_minute": elif self.configMode == "set_minute":
self.configMode = "normal" self.configMode = "normal"
self.setLcdText(f"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.alarmHour:02d}:{self.alarmMinute:02d}") print(f"Alarm time saved: {self.alarmTime.hour:02d}:{self.alarmTime.minute:02d}")
lastLcdText: str = "" lastLcdText: str = ""
def setLcdText(self, text: str): def setLcdText(self, text: str):
@@ -176,6 +220,13 @@ pins = {
"buzzer": 12, "buzzer": 12,
} }
alarm_clock = AlarmClock(pins) 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() alarm_clock.start()