Add audio playback functionality and enhance alarm action reset logic

This commit is contained in:
Aaro Varis
2026-02-05 09:29:29 +02:00
parent 207ae2922a
commit 989c831732

39
init.py
View File

@@ -5,6 +5,7 @@ from datetime import date, datetime, timedelta
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from typing import Callable from typing import Callable
import requests import requests
import subprocess
from grove.gpio import GPIO from grove.gpio import GPIO
from grove.display.jhd1802 import JHD1802 from grove.display.jhd1802 import JHD1802
@@ -49,6 +50,19 @@ 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"]
def playAudio(filePath: str) -> None:
"""
Play an audio file through the Raspberry Pi's standard aux output.
Args:
filePath: Path to the audio file (.wav, .mp3, .ogg, etc.)
"""
if filePath.endswith(".wav"):
subprocess.Popen(["aplay", filePath], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else:
# Use mpg123 for mp3, or ffplay/mpv as fallback for other formats
subprocess.Popen(["mpg123", "-q", filePath], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
class WakeUpAction: class WakeUpAction:
offsetSeconds: int # how many seconds before alarm time to trigger offsetSeconds: int # how many seconds before alarm time to trigger
action: Callable[[], None] action: Callable[[], None]
@@ -74,7 +88,8 @@ 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
alarmTime: datetime = datetime.now(ZoneInfo("Europe/Helsinki")).replace(hour=9, minute=13, second=0, microsecond=0) alarmTime: datetime = datetime.now(ZoneInfo("Europe/Helsinki")).replace(hour=9, minute=32, second=0, microsecond=0)
actionsResetForToday: bool = False
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)
@@ -88,12 +103,17 @@ class AlarmClock:
self.wakeupActions.append(WakeUpAction(offsetSeconds, action)) self.wakeupActions.append(WakeUpAction(offsetSeconds, action))
def resetWakeUpActions(self): def resetWakeUpActions(self):
"""Reset all wakeup actions so they can trigger again tomorrow""" """Reset all wakeup actions so they can trigger again"""
for action in self.wakeupActions: for action in self.wakeupActions:
action.triggered = False action.triggered = False
self.actionsResetForToday = True
print("Wakeup actions reset")
def checkWakeUpActions(self): def checkWakeUpActions(self):
"""Check and trigger any wakeup actions that are due""" """Check and trigger any wakeup actions that are due"""
if not self.wakeupActions:
return
now = datetime.now(ZoneInfo(city.timezone)) now = datetime.now(ZoneInfo(city.timezone))
today_alarm = now.replace( today_alarm = now.replace(
hour=self.alarmTime.hour, hour=self.alarmTime.hour,
@@ -102,6 +122,20 @@ class AlarmClock:
microsecond=0 microsecond=0
) )
# Find the earliest action (largest offset)
max_offset = max(action.offsetSeconds for action in self.wakeupActions)
first_trigger_time = today_alarm - timedelta(seconds=max_offset)
reset_time = first_trigger_time - timedelta(seconds=10)
alarm_window_end = today_alarm + timedelta(minutes=1)
# Reset actions 10 seconds before the first one should trigger
if now >= reset_time and now < first_trigger_time and not self.actionsResetForToday:
self.resetWakeUpActions()
# After alarm window ends, allow reset to happen again tomorrow
if now >= alarm_window_end:
self.actionsResetForToday = False
for wakeupAction in self.wakeupActions: for wakeupAction in self.wakeupActions:
if wakeupAction.triggered: if wakeupAction.triggered:
continue continue
@@ -226,6 +260,7 @@ alarm_clock.addWakeUpAction(120, lambda: print("2 minutes to alarm!")) # 2 minu
alarm_clock.addWakeUpAction(90, lambda: setShellyPlugState(shelly_deviceId, True)) # activate plug 90s 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(30, lambda: print("30 seconds to alarm!")) # 30 seconds before alarm
alarm_clock.addWakeUpAction(0, lambda: print("Alarm triggered!")) # At alarm time alarm_clock.addWakeUpAction(0, lambda: print("Alarm triggered!")) # At alarm time
alarm_clock.addWakeUpAction(0, lambda: playAudio("./boxing_bell_multiple.wav")) # Play sound at alarm time
alarm_clock.start() alarm_clock.start()