Intent target matching and media player enhancements (#115445)
* Working * Tests are passing * Fix climate * Requested changes from review
This commit is contained in:
parent
8401b05d40
commit
7923471b94
13 changed files with 1734 additions and 589 deletions
|
@ -12,27 +12,29 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers import intent
|
||||
|
||||
from . import ATTR_MEDIA_VOLUME_LEVEL, DOMAIN
|
||||
from .const import MediaPlayerEntityFeature, MediaPlayerState
|
||||
|
||||
INTENT_MEDIA_PAUSE = "HassMediaPause"
|
||||
INTENT_MEDIA_UNPAUSE = "HassMediaUnpause"
|
||||
INTENT_MEDIA_NEXT = "HassMediaNext"
|
||||
INTENT_SET_VOLUME = "HassSetVolume"
|
||||
|
||||
DATA_LAST_PAUSED = f"{DOMAIN}.last_paused"
|
||||
|
||||
|
||||
async def async_setup_intents(hass: HomeAssistant) -> None:
|
||||
"""Set up the media_player intents."""
|
||||
intent.async_register(
|
||||
hass,
|
||||
intent.ServiceIntentHandler(INTENT_MEDIA_UNPAUSE, DOMAIN, SERVICE_MEDIA_PLAY),
|
||||
)
|
||||
intent.async_register(
|
||||
hass,
|
||||
intent.ServiceIntentHandler(INTENT_MEDIA_PAUSE, DOMAIN, SERVICE_MEDIA_PAUSE),
|
||||
)
|
||||
intent.async_register(hass, MediaUnpauseHandler())
|
||||
intent.async_register(hass, MediaPauseHandler())
|
||||
intent.async_register(
|
||||
hass,
|
||||
intent.ServiceIntentHandler(
|
||||
INTENT_MEDIA_NEXT, DOMAIN, SERVICE_MEDIA_NEXT_TRACK
|
||||
INTENT_MEDIA_NEXT,
|
||||
DOMAIN,
|
||||
SERVICE_MEDIA_NEXT_TRACK,
|
||||
required_domains={DOMAIN},
|
||||
required_features=MediaPlayerEntityFeature.NEXT_TRACK,
|
||||
required_states={MediaPlayerState.PLAYING},
|
||||
),
|
||||
)
|
||||
intent.async_register(
|
||||
|
@ -41,10 +43,88 @@ async def async_setup_intents(hass: HomeAssistant) -> None:
|
|||
INTENT_SET_VOLUME,
|
||||
DOMAIN,
|
||||
SERVICE_VOLUME_SET,
|
||||
extra_slots={
|
||||
required_domains={DOMAIN},
|
||||
required_states={MediaPlayerState.PLAYING},
|
||||
required_features=MediaPlayerEntityFeature.VOLUME_SET,
|
||||
required_slots={
|
||||
ATTR_MEDIA_VOLUME_LEVEL: vol.All(
|
||||
vol.Range(min=0, max=100), lambda val: val / 100
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue