Skip to content

Commit 3ef7ee0

Browse files
authored
Merge pull request #17 from rhasspy/synesthesiam-20240522-timers
Add timer events
2 parents 18d1446 + 28c1511 commit 3ef7ee0

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## 1.5.4
44

5+
- Add support for voice timers
6+
- `timer-started`
7+
- `timer-updated`
8+
- `timer-cancelled`
9+
- `timer-finished`
510
- Add `speaker` field to `detect` event
611
- Refactor HTTP servers
712

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ Control of one or more remote voice satellites connected to a central server.
228228
* `streaming-started` - satellite has started streaming audio to the server
229229
* `streaming-stopped` - satellite has stopped streaming audio to the server
230230

231+
### Timers
232+
233+
* `timer-started` - a new timer has started
234+
* `timer-updated` - timer has been paused/resumed or time has been added/removed
235+
* `timer-cancelled` - timer was cancelled
236+
* `timer-finished` - timer finished without being cancelled
231237

232238
## Event Flow
233239

wyoming/timer.py

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
"""Support for voice timers."""
2+
3+
from dataclasses import dataclass
4+
from typing import Optional
5+
6+
from .event import Event, Eventable
7+
8+
DOMAIN = "timer"
9+
_STARTED_TYPE = "timer-started"
10+
_UPDATED_TYPE = "timer-updated"
11+
_CANCELLED_TYPE = "timer-cancelled"
12+
_FINISHED_TYPE = "timer-finished"
13+
14+
15+
@dataclass
16+
class TimerStarted(Eventable):
17+
"""New timer was started."""
18+
19+
id: str
20+
"""Unique id of timer."""
21+
22+
total_seconds: int
23+
"""Total number of seconds the timer will run for."""
24+
25+
name: Optional[str] = None
26+
"""Optional name provided by user."""
27+
28+
start_hours: Optional[int] = None
29+
"""Number of hours users requested the timer to run for."""
30+
31+
start_minutes: Optional[int] = None
32+
"""Number of minutes users requested the timer to run for."""
33+
34+
start_seconds: Optional[int] = None
35+
"""Number of minutes users requested the timer to run for."""
36+
37+
@staticmethod
38+
def is_type(event_type: str) -> bool:
39+
return event_type == _STARTED_TYPE
40+
41+
def event(self) -> Event:
42+
data = {"id": self.id, "total_seconds": self.total_seconds}
43+
if self.name is not None:
44+
data["name"] = self.name
45+
46+
if self.start_hours is not None:
47+
data["start_hours"] = self.start_hours
48+
49+
if self.start_minutes is not None:
50+
data["start_minutes"] = self.start_minutes
51+
52+
if self.start_seconds is not None:
53+
data["start_seconds"] = self.start_seconds
54+
55+
return Event(
56+
type=_STARTED_TYPE,
57+
data=data,
58+
)
59+
60+
@staticmethod
61+
def from_event(event: Event) -> "TimerStarted":
62+
return TimerStarted(
63+
id=event.data["id"],
64+
total_seconds=event.data["total_seconds"],
65+
name=event.data.get("name"),
66+
start_hours=event.data.get("start_hours"),
67+
start_minutes=event.data.get("start_minutes"),
68+
start_seconds=event.data.get("start_seconds"),
69+
)
70+
71+
72+
@dataclass
73+
class TimerUpdated(Eventable):
74+
"""Existing timer was paused, resumed, or had time added or removed."""
75+
76+
id: str
77+
"""Unique id of timer."""
78+
79+
is_active: bool
80+
"""True if timer is running."""
81+
82+
total_seconds: int
83+
"""Number of seconds left on the timer."""
84+
85+
@staticmethod
86+
def is_type(event_type: str) -> bool:
87+
return event_type == _UPDATED_TYPE
88+
89+
def event(self) -> Event:
90+
return Event(
91+
type=_UPDATED_TYPE,
92+
data={
93+
"id": self.id,
94+
"is_active": self.is_active,
95+
"total_seconds": self.total_seconds,
96+
},
97+
)
98+
99+
@staticmethod
100+
def from_event(event: Event) -> "TimerUpdated":
101+
return TimerUpdated(
102+
id=event.data["id"],
103+
is_active=event.data["is_active"],
104+
total_seconds=event.data["total_seconds"],
105+
)
106+
107+
108+
@dataclass
109+
class TimerCancelled(Eventable):
110+
"""Existing timer was cancelled."""
111+
112+
id: str
113+
"""Unique id of timer."""
114+
115+
@staticmethod
116+
def is_type(event_type: str) -> bool:
117+
return event_type == _CANCELLED_TYPE
118+
119+
def event(self) -> Event:
120+
return Event(
121+
type=_CANCELLED_TYPE,
122+
data={"id": self.id},
123+
)
124+
125+
@staticmethod
126+
def from_event(event: Event) -> "TimerCancelled":
127+
return TimerCancelled(id=event.data["id"])
128+
129+
130+
@dataclass
131+
class TimerFinished(Eventable):
132+
"""Existing timer finished without being cancelled."""
133+
134+
id: str
135+
"""Unique id of timer."""
136+
137+
@staticmethod
138+
def is_type(event_type: str) -> bool:
139+
return event_type == _FINISHED_TYPE
140+
141+
def event(self) -> Event:
142+
return Event(
143+
type=_FINISHED_TYPE,
144+
data={"id": self.id},
145+
)
146+
147+
@staticmethod
148+
def from_event(event: Event) -> "TimerFinished":
149+
return TimerFinished(id=event.data["id"])

0 commit comments

Comments
 (0)