1 """Intents for the media_player integration."""
3 from collections.abc
import Iterable
4 from dataclasses
import dataclass, field
7 import voluptuous
as vol
10 SERVICE_MEDIA_NEXT_TRACK,
13 SERVICE_MEDIA_PREVIOUS_TRACK,
19 from .
import ATTR_MEDIA_VOLUME_LEVEL, DOMAIN, MediaPlayerDeviceClass
20 from .const
import MediaPlayerEntityFeature, MediaPlayerState
22 INTENT_MEDIA_PAUSE =
"HassMediaPause"
23 INTENT_MEDIA_UNPAUSE =
"HassMediaUnpause"
24 INTENT_MEDIA_NEXT =
"HassMediaNext"
25 INTENT_MEDIA_PREVIOUS =
"HassMediaPrevious"
26 INTENT_SET_VOLUME =
"HassSetVolume"
31 """Information about last media players that were paused by voice."""
33 timestamp: float |
None =
None
34 context: Context |
None =
None
35 entity_ids: set[str] = field(default_factory=set)
38 """Clear timestamp and entities."""
43 def update(self, context: Context |
None, entity_ids: Iterable[str]) ->
None:
44 """Update last paused group."""
51 """Return True if timestamp is set."""
52 return self.
timestamptimestamp
is not None
56 """Set up the media_player intents."""
61 intent.async_register(
63 intent.ServiceIntentHandler(
66 SERVICE_MEDIA_NEXT_TRACK,
67 required_domains={DOMAIN},
68 required_features=MediaPlayerEntityFeature.NEXT_TRACK,
69 required_states={MediaPlayerState.PLAYING},
70 description=
"Skips a media player to the next item",
72 device_classes={MediaPlayerDeviceClass},
75 intent.async_register(
77 intent.ServiceIntentHandler(
78 INTENT_MEDIA_PREVIOUS,
80 SERVICE_MEDIA_PREVIOUS_TRACK,
81 required_domains={DOMAIN},
82 required_features=MediaPlayerEntityFeature.PREVIOUS_TRACK,
83 required_states={MediaPlayerState.PLAYING},
84 description=
"Replays the previous item for a media player",
86 device_classes={MediaPlayerDeviceClass},
89 intent.async_register(
91 intent.ServiceIntentHandler(
95 required_domains={DOMAIN},
96 required_states={MediaPlayerState.PLAYING},
97 required_features=MediaPlayerEntityFeature.VOLUME_SET,
99 ATTR_MEDIA_VOLUME_LEVEL: vol.All(
100 vol.Coerce(int), vol.Range(min=0, max=100),
lambda val: val / 100
103 description=
"Sets the volume of a media player",
105 device_classes={MediaPlayerDeviceClass},
111 """Handler for pause intent. Records last paused media players."""
113 def __init__(self, last_paused: LastPaused) ->
None:
114 """Initialize handler."""
119 required_domains={DOMAIN},
120 required_features=MediaPlayerEntityFeature.PAUSE,
121 required_states={MediaPlayerState.PLAYING},
122 description=
"Pauses a media player",
124 device_classes={MediaPlayerDeviceClass},
130 intent_obj: intent.Intent,
131 match_result: intent.MatchTargetsResult,
132 match_constraints: intent.MatchTargetsConstraints,
133 match_preferences: intent.MatchTargetsPreferences |
None =
None,
134 ) -> intent.IntentResponse:
135 """Record last paused media players."""
136 if match_result.is_match:
139 intent_obj.context, (s.entity_id
for s
in match_result.states)
143 intent_obj, match_result, match_constraints
148 """Handler for unpause/resume intent. Uses last paused media players."""
150 def __init__(self, last_paused: LastPaused) ->
None:
151 """Initialize handler."""
153 INTENT_MEDIA_UNPAUSE,
156 required_domains={DOMAIN},
157 required_states={MediaPlayerState.PAUSED},
158 description=
"Resumes a media player",
160 device_classes={MediaPlayerDeviceClass},
166 intent_obj: intent.Intent,
167 match_result: intent.MatchTargetsResult,
168 match_constraints: intent.MatchTargetsConstraints,
169 match_preferences: intent.MatchTargetsPreferences |
None =
None,
170 ) -> intent.IntentResponse:
171 """Unpause last paused media players."""
172 if match_result.is_match
and (
not match_constraints.name)
and self.
last_pausedlast_paused:
173 assert self.
last_pausedlast_paused.timestamp
is not None
177 recent_state: State |
None =
None
178 for state
in match_result.states:
179 if (state.last_changed_timestamp <= self.
last_pausedlast_paused.timestamp)
or (
180 state.context == self.
last_pausedlast_paused.context
184 if (recent_state
is None)
or (
185 state.last_changed_timestamp > recent_state.last_changed_timestamp
189 if recent_state
is not None:
191 match_result.states = [recent_state]
195 targeted_ids = {s.entity_id
for s
in match_result.states}
196 overlapping_ids = targeted_ids.intersection(self.
last_pausedlast_paused.entity_ids)
198 match_result.states = [
199 s
for s
in match_result.states
if s.entity_id
in overlapping_ids
205 intent_obj, match_result, match_constraints
IssData update(pyiss.ISS iss)