2024-02-20 03:28:42 +00:00
|
|
|
"""Intents for the media_player integration."""
|
|
|
|
|
|
|
|
import voluptuous as vol
|
|
|
|
|
|
|
|
from homeassistant.const import (
|
|
|
|
SERVICE_MEDIA_NEXT_TRACK,
|
|
|
|
SERVICE_MEDIA_PAUSE,
|
|
|
|
SERVICE_MEDIA_PLAY,
|
|
|
|
SERVICE_VOLUME_SET,
|
|
|
|
)
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from homeassistant.helpers import intent
|
|
|
|
|
|
|
|
from . import ATTR_MEDIA_VOLUME_LEVEL, DOMAIN
|
2024-05-08 02:01:03 +00:00
|
|
|
from .const import MediaPlayerEntityFeature, MediaPlayerState
|
2024-02-20 03:28:42 +00:00
|
|
|
|
|
|
|
INTENT_MEDIA_PAUSE = "HassMediaPause"
|
|
|
|
INTENT_MEDIA_UNPAUSE = "HassMediaUnpause"
|
|
|
|
INTENT_MEDIA_NEXT = "HassMediaNext"
|
|
|
|
INTENT_SET_VOLUME = "HassSetVolume"
|
|
|
|
|
2024-05-08 02:01:03 +00:00
|
|
|
DATA_LAST_PAUSED = f"{DOMAIN}.last_paused"
|
|
|
|
|
2024-02-20 03:28:42 +00:00
|
|
|
|
|
|
|
async def async_setup_intents(hass: HomeAssistant) -> None:
|
|
|
|
"""Set up the media_player intents."""
|
2024-05-08 02:01:03 +00:00
|
|
|
intent.async_register(hass, MediaUnpauseHandler())
|
|
|
|
intent.async_register(hass, MediaPauseHandler())
|
2024-02-20 03:28:42 +00:00
|
|
|
intent.async_register(
|
|
|
|
hass,
|
|
|
|
intent.ServiceIntentHandler(
|
2024-05-08 02:01:03 +00:00
|
|
|
INTENT_MEDIA_NEXT,
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_MEDIA_NEXT_TRACK,
|
|
|
|
required_domains={DOMAIN},
|
|
|
|
required_features=MediaPlayerEntityFeature.NEXT_TRACK,
|
|
|
|
required_states={MediaPlayerState.PLAYING},
|
2024-02-20 03:28:42 +00:00
|
|
|
),
|
|
|
|
)
|
|
|
|
intent.async_register(
|
|
|
|
hass,
|
|
|
|
intent.ServiceIntentHandler(
|
|
|
|
INTENT_SET_VOLUME,
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_VOLUME_SET,
|
2024-05-08 02:01:03 +00:00
|
|
|
required_domains={DOMAIN},
|
|
|
|
required_states={MediaPlayerState.PLAYING},
|
|
|
|
required_features=MediaPlayerEntityFeature.VOLUME_SET,
|
|
|
|
required_slots={
|
2024-02-20 03:28:42 +00:00
|
|
|
ATTR_MEDIA_VOLUME_LEVEL: vol.All(
|
2024-05-10 15:27:04 +00:00
|
|
|
vol.Coerce(int), vol.Range(min=0, max=100), lambda val: val / 100
|
2024-02-20 03:28:42 +00:00
|
|
|
)
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2024-05-08 02:01:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MediaPauseHandler(intent.ServiceIntentHandler):
|
|
|
|
"""Handler for pause intent. Records last paused media players."""
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
"""Initialize handler."""
|
|
|
|
super().__init__(
|
|
|
|
INTENT_MEDIA_PAUSE,
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_MEDIA_PAUSE,
|
|
|
|
required_domains={DOMAIN},
|
|
|
|
required_features=MediaPlayerEntityFeature.PAUSE,
|
|
|
|
required_states={MediaPlayerState.PLAYING},
|
|
|
|
)
|
|
|
|
|
|
|
|
async def async_handle_states(
|
|
|
|
self,
|
|
|
|
intent_obj: intent.Intent,
|
|
|
|
match_result: intent.MatchTargetsResult,
|
|
|
|
match_constraints: intent.MatchTargetsConstraints,
|
|
|
|
match_preferences: intent.MatchTargetsPreferences | None = None,
|
|
|
|
) -> intent.IntentResponse:
|
|
|
|
"""Record last paused media players."""
|
|
|
|
hass = intent_obj.hass
|
|
|
|
|
|
|
|
if match_result.is_match:
|
|
|
|
# Save entity ids of paused media players
|
|
|
|
hass.data[DATA_LAST_PAUSED] = {s.entity_id for s in match_result.states}
|
|
|
|
|
|
|
|
return await super().async_handle_states(
|
|
|
|
intent_obj, match_result, match_constraints
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class MediaUnpauseHandler(intent.ServiceIntentHandler):
|
|
|
|
"""Handler for unpause/resume intent. Uses last paused media players."""
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
"""Initialize handler."""
|
|
|
|
super().__init__(
|
|
|
|
INTENT_MEDIA_UNPAUSE,
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_MEDIA_PLAY,
|
|
|
|
required_domains={DOMAIN},
|
|
|
|
required_states={MediaPlayerState.PAUSED},
|
|
|
|
)
|
|
|
|
|
|
|
|
async def async_handle_states(
|
|
|
|
self,
|
|
|
|
intent_obj: intent.Intent,
|
|
|
|
match_result: intent.MatchTargetsResult,
|
|
|
|
match_constraints: intent.MatchTargetsConstraints,
|
|
|
|
match_preferences: intent.MatchTargetsPreferences | None = None,
|
|
|
|
) -> intent.IntentResponse:
|
|
|
|
"""Unpause last paused media players."""
|
|
|
|
hass = intent_obj.hass
|
|
|
|
|
|
|
|
if (
|
|
|
|
match_result.is_match
|
|
|
|
and (not match_constraints.name)
|
|
|
|
and (last_paused := hass.data.get(DATA_LAST_PAUSED))
|
|
|
|
):
|
|
|
|
# Resume only the previously paused media players if they are in the
|
|
|
|
# targeted set.
|
|
|
|
targeted_ids = {s.entity_id for s in match_result.states}
|
|
|
|
overlapping_ids = targeted_ids.intersection(last_paused)
|
|
|
|
if overlapping_ids:
|
|
|
|
match_result.states = [
|
|
|
|
s for s in match_result.states if s.entity_id in overlapping_ids
|
|
|
|
]
|
|
|
|
|
|
|
|
return await super().async_handle_states(
|
|
|
|
intent_obj, match_result, match_constraints
|
|
|
|
)
|