Add audio playback functionality and enhance alarm action reset logic
This commit is contained in:
39
init.py
39
init.py
@@ -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()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user