Weckerfunktoin vollständig implementiert
This commit is contained in:
Binary file not shown.
BIN
__pycache__/wecker_control.cpython-310.pyc
Normal file
BIN
__pycache__/wecker_control.cpython-310.pyc
Normal file
Binary file not shown.
70
main.py
70
main.py
@@ -9,6 +9,7 @@ import re
|
|||||||
import asyncio
|
import asyncio
|
||||||
from weather_jetzt import get_weather_for_location
|
from weather_jetzt import get_weather_for_location
|
||||||
from timer_control import parse_time, start_timer, stop_timer, timer_status_info, format_duration
|
from timer_control import parse_time, start_timer, stop_timer, timer_status_info, format_duration
|
||||||
|
from wecker_control import parse_time_wecker, minutes_until, start_wecker, stop_wecker, wecker_status_info, calculate_target_datetime
|
||||||
|
|
||||||
#test
|
#test
|
||||||
|
|
||||||
@@ -93,7 +94,7 @@ INTENTS = {
|
|||||||
# "duration": r"(\w+)\s*(sekunden|sekunde|minuten|minute|stunden|stunde)"
|
# "duration": r"(\w+)\s*(sekunden|sekunde|minuten|minute|stunden|stunde)"
|
||||||
"duration": r"((?:\w+)\s*(?:sekunden|sekunde|minuten|minute|stunden|stunde))"
|
"duration": r"((?:\w+)\s*(?:sekunden|sekunde|minuten|minute|stunden|stunde))"
|
||||||
|
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"stop": {
|
"stop": {
|
||||||
"keywords": ["stopp", "stoppe", "beende"],
|
"keywords": ["stopp", "stoppe", "beende"],
|
||||||
@@ -104,6 +105,25 @@ INTENTS = {
|
|||||||
"required_slots": {}
|
"required_slots": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"wecker": {
|
||||||
|
"keywords": ["wecker", "timer"],
|
||||||
|
"actions": {
|
||||||
|
"start": {
|
||||||
|
"keywords": ["erstelle", "stelle"],
|
||||||
|
"required_slots": {
|
||||||
|
"timeSet": r"\b([\w]+)\s*uhr(?:\s*([\w]+))?\b"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"stop": {
|
||||||
|
"keywords": ["stopp", "stoppe", "entferne"],
|
||||||
|
"required_slots": {}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"keywords": ["status", "läuft", "noch"],
|
||||||
|
"required_slots": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +142,7 @@ def detect_intent(text):
|
|||||||
# =========================
|
# =========================
|
||||||
|
|
||||||
|
|
||||||
|
## WEATHER
|
||||||
def weather_skill(slots):
|
def weather_skill(slots):
|
||||||
location = slots["location"]
|
location = slots["location"]
|
||||||
result = asyncio.run(get_weather_for_location(location))
|
result = asyncio.run(get_weather_for_location(location))
|
||||||
@@ -133,6 +153,7 @@ def weather_skill(slots):
|
|||||||
return f"Keine Wetterdaten verfügbar"
|
return f"Keine Wetterdaten verfügbar"
|
||||||
#return f"Das Wetter in {location} ist sonnig bei 20 Grad."
|
#return f"Das Wetter in {location} ist sonnig bei 20 Grad."
|
||||||
|
|
||||||
|
## TIMER
|
||||||
def start_timer_skill(slots):
|
def start_timer_skill(slots):
|
||||||
duration = slots["duration"]
|
duration = slots["duration"]
|
||||||
seconds = parse_time(duration)
|
seconds = parse_time(duration)
|
||||||
@@ -162,7 +183,40 @@ def status_timer_skill(slots):
|
|||||||
else:
|
else:
|
||||||
return f"Es läuft kein Timer"
|
return f"Es läuft kein Timer"
|
||||||
|
|
||||||
|
#ALARM
|
||||||
|
def start_wecker_skill(slots):
|
||||||
|
parsed = parse_time_wecker(slots["timeSet"])
|
||||||
|
|
||||||
|
if not parsed:
|
||||||
|
return "Die Uhrzeit konnte nicht erkannt werden."
|
||||||
|
|
||||||
|
hour, minute = parsed
|
||||||
|
target = calculate_target_datetime(hour, minute)
|
||||||
|
|
||||||
|
start_wecker(target)
|
||||||
|
minutes = minutes_until(target)
|
||||||
|
|
||||||
|
return f"Wecker für {hour:02d}:{minute:02d} wurde gestellt er klingelt in {minutes} minuten"
|
||||||
|
|
||||||
|
def stopp_wecker_skill(slots):
|
||||||
|
stop_wecker()
|
||||||
|
print("Wecker wurde gestoppt")
|
||||||
|
return f"Wecker wurde gestoppt"
|
||||||
|
|
||||||
|
def status_wecker_skill(slots):
|
||||||
|
|
||||||
|
info = wecker_status_info()
|
||||||
|
|
||||||
|
if info["status"] == "running":
|
||||||
|
target_time = info["target_time"]
|
||||||
|
return f"Ein Wecker wurde bereits auf {wecker_target_time} gestellt"
|
||||||
|
elif info["status"] == "finished":
|
||||||
|
return f"Der Wecker ist abgelaufen"
|
||||||
|
elif info["status"] == "stopped":
|
||||||
|
return f"Der Wecker wurde gestoppt, es ist kein Wecker gestellt"
|
||||||
|
else:
|
||||||
|
return f"Es ist kein Wecker gestellt"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SKILLS = {
|
SKILLS = {
|
||||||
@@ -170,7 +224,12 @@ SKILLS = {
|
|||||||
"timer": {
|
"timer": {
|
||||||
"start": start_timer_skill,
|
"start": start_timer_skill,
|
||||||
"stop": stopp_timer_skill,
|
"stop": stopp_timer_skill,
|
||||||
"status": status_timer_skill
|
"status": status_timer_skill,
|
||||||
|
},
|
||||||
|
"wecker": {
|
||||||
|
"start": start_wecker_skill,
|
||||||
|
"stop": stopp_wecker_skill,
|
||||||
|
"status": status_wecker_skill
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +305,7 @@ def check_required(text):
|
|||||||
if slot not in context["slots"]:
|
if slot not in context["slots"]:
|
||||||
match = re.search(pattern, text)
|
match = re.search(pattern, text)
|
||||||
if match:
|
if match:
|
||||||
context["slots"][slot] = match.group(1) # schau an
|
context["slots"][slot] = match.group(0) #alles slots
|
||||||
else:
|
else:
|
||||||
context["pending_slot"] = slot
|
context["pending_slot"] = slot
|
||||||
ask_for_slot(slot)
|
ask_for_slot(slot)
|
||||||
@@ -268,7 +327,8 @@ def check_required(text):
|
|||||||
def ask_for_slot(slot):
|
def ask_for_slot(slot):
|
||||||
questions = {
|
questions = {
|
||||||
"location": "Für welchen Ort?",
|
"location": "Für welchen Ort?",
|
||||||
"duration": "Wie lange soll der Timer laufen?"
|
"duration": "Wie lange soll der Timer laufen?",
|
||||||
|
"timeSet": "Zu welcher Uhrzeit soll der Wecker klingeln?"
|
||||||
}
|
}
|
||||||
speak(questions.get(slot, "Bitte spezifizieren."))
|
speak(questions.get(slot, "Bitte spezifizieren."))
|
||||||
|
|
||||||
|
|||||||
147
wecker_control.py
Normal file
147
wecker_control.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import time
|
||||||
|
import threading
|
||||||
|
from text2numde import text2num, is_number, sentence2num
|
||||||
|
from playsound3 import playsound
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import re
|
||||||
|
import math
|
||||||
|
|
||||||
|
wecker_thread = None
|
||||||
|
wecker_stop = threading.Event()
|
||||||
|
wecker_status = "idle"
|
||||||
|
wecker_target_time: datetime | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_time_wecker(text):
|
||||||
|
|
||||||
|
text = text.lower().strip()
|
||||||
|
|
||||||
|
match = re.search(r"\b([\w]+)\s*uhr(?:\s*([\w]+))?\b", text)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
|
hour_text = match.group(1)
|
||||||
|
minute_text= match.group(2)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
hour = text2num(hour_text)
|
||||||
|
minute = text2num(minute_text) if minute_text else 0
|
||||||
|
except ValueError:
|
||||||
|
print("Konnte die Zahl nicht erkennen.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if hour < 0 or hour > 23:
|
||||||
|
return None
|
||||||
|
if minute < 0 or minute > 59:
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f"{hour:02d}:{minute:02d}")
|
||||||
|
return hour, minute
|
||||||
|
|
||||||
|
def calculate_target_datetime(hour: int, minute: int) -> datetime:
|
||||||
|
now = datetime.now()
|
||||||
|
|
||||||
|
target = now.replace(hour=hour, minute=minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
if target <= now:
|
||||||
|
target += timedelta(days=1)
|
||||||
|
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def minutes_until(target: datetime) -> int:
|
||||||
|
#return int(((target - now)).total_seconds() // 60) hatte das davor aber das hat abgerundet
|
||||||
|
seconds = (target - datetime.now()).total_seconds()
|
||||||
|
return math.ceil(seconds / 60)
|
||||||
|
|
||||||
|
|
||||||
|
def start_wecker(target_time: datetime):
|
||||||
|
global wecker_thread, wecker_status, wecker_target_time
|
||||||
|
|
||||||
|
if wecker_status == "running":
|
||||||
|
return False # wecker läuft bereits
|
||||||
|
|
||||||
|
wecker_stop.clear()
|
||||||
|
wecker_target_time = target_time
|
||||||
|
wecker_status = "running"
|
||||||
|
|
||||||
|
def run():
|
||||||
|
global wecker_status
|
||||||
|
seconds = (wecker_target_time - datetime.now()).total_seconds()
|
||||||
|
if seconds < 0:
|
||||||
|
seconds = 0
|
||||||
|
|
||||||
|
if not wecker_stop.wait(seconds):
|
||||||
|
wecker_status = "finished"
|
||||||
|
print("wecker abgelaufen") # """ TTS """
|
||||||
|
|
||||||
|
wecker_thread = threading.Thread(target=run, daemon=True)
|
||||||
|
wecker_thread.start()
|
||||||
|
return True
|
||||||
|
"""
|
||||||
|
print(f"wecker startet für {seconds} Sekunden...")
|
||||||
|
time.sleep(seconds)
|
||||||
|
print("wecker abgelaufen!")
|
||||||
|
playsound("/home/tino/Desktop/Abschlussprojekt/test assistant/cloneAssistantAllInOne/RasPi_Voice_Assistant--WIP/clock-alarm-8761.mp3")
|
||||||
|
sound.stop()
|
||||||
|
"""
|
||||||
|
|
||||||
|
""" # Beispielnutzung
|
||||||
|
spoken_input = "eine sekunde" # This could come from a voice assistant
|
||||||
|
seconds = parse_time(spoken_input)
|
||||||
|
if seconds:
|
||||||
|
start_wecker(seconds) """
|
||||||
|
|
||||||
|
def stop_wecker():
|
||||||
|
global wecker_status
|
||||||
|
if wecker_status != "running":
|
||||||
|
print("Kein wecker gestellt")
|
||||||
|
return False
|
||||||
|
|
||||||
|
wecker_stop.set()
|
||||||
|
wecker_status = "stopped"
|
||||||
|
return True
|
||||||
|
|
||||||
|
def wecker_status_info():
|
||||||
|
if wecker_status != "running":
|
||||||
|
return {"status": wecker_status, "target_time": 0}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "running",
|
||||||
|
"target_time": wecker_target_time
|
||||||
|
}
|
||||||
|
|
||||||
|
def format_duration(seconds):
|
||||||
|
if seconds < 60:
|
||||||
|
return f"{seconds} {second_text(seconds)}"
|
||||||
|
|
||||||
|
minutes = seconds // 60
|
||||||
|
secs = seconds % 60
|
||||||
|
|
||||||
|
if minutes < 10:
|
||||||
|
if secs == 0:
|
||||||
|
return f"{minutes} {minute_text(minutes)}"
|
||||||
|
return f"{minutes} {minute_text(minutes)} und {secs} {second_text(secs)}"
|
||||||
|
|
||||||
|
if minutes < 60:
|
||||||
|
return f"{minutes} {minute_text(minutes)}"
|
||||||
|
|
||||||
|
hours = minutes // 60
|
||||||
|
mins = minutes % 60
|
||||||
|
|
||||||
|
if mins == 0:
|
||||||
|
return f"{hours} {hour_text(hours)}"
|
||||||
|
return f"{hours} {hour_text(hours)} und {mins} {minute_text(mins)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def minute_text(n):
|
||||||
|
return "Minute" if n == 1 else "Minuten"
|
||||||
|
|
||||||
|
def second_text(n):
|
||||||
|
return "Sekunde" if n == 1 else "Sekunden"
|
||||||
|
|
||||||
|
def hour_text(n):
|
||||||
|
return "Stunde" if n == 1 else "Stunden"
|
||||||
Reference in New Issue
Block a user