mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 23:41:48 -05:00
Add media_player.paused trigger
This commit is contained in:
@@ -389,6 +389,11 @@
|
||||
}
|
||||
},
|
||||
"name": "When a media player starts playing"
|
||||
},
|
||||
"paused": {
|
||||
"description": "Triggers when a media player pauses.",
|
||||
"description_configured": "Triggers when a media player pauses",
|
||||
"name": "When a media player pauses"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ from homeassistant.const import (
|
||||
CONF_OPTIONS,
|
||||
CONF_TARGET,
|
||||
STATE_OFF,
|
||||
STATE_PAUSED,
|
||||
STATE_PLAYING,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
@@ -48,6 +49,13 @@ PLAYING_TRIGGER_SCHEMA = vol.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
PAUSED_TRIGGER_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_OPTIONS, default={}): {},
|
||||
vol.Required(CONF_TARGET): cv.TARGET_FIELDS,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class MediaPlayerTurnsOnTrigger(Trigger):
|
||||
"""Trigger for when a media player turns on."""
|
||||
@@ -259,10 +267,78 @@ class MediaPlayerPlayingTrigger(Trigger):
|
||||
)
|
||||
|
||||
|
||||
class MediaPlayerPausedTrigger(Trigger):
|
||||
"""Trigger for when a media player pauses."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
async def async_validate_config(
|
||||
cls, hass: HomeAssistant, config: ConfigType
|
||||
) -> ConfigType:
|
||||
"""Validate config."""
|
||||
return cast(ConfigType, PAUSED_TRIGGER_SCHEMA(config))
|
||||
|
||||
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
|
||||
"""Initialize the media player paused trigger."""
|
||||
super().__init__(hass, config)
|
||||
if TYPE_CHECKING:
|
||||
assert config.target is not None
|
||||
self._target = config.target
|
||||
|
||||
@override
|
||||
async def async_attach_runner(
|
||||
self, run_action: TriggerActionRunner
|
||||
) -> CALLBACK_TYPE:
|
||||
"""Attach the trigger to an action runner."""
|
||||
|
||||
@callback
|
||||
def state_change_listener(
|
||||
target_state_change_data: TargetStateChangedData,
|
||||
) -> None:
|
||||
"""Listen for state changes and call action."""
|
||||
event = target_state_change_data.state_change_event
|
||||
entity_id = event.data["entity_id"]
|
||||
from_state = event.data["old_state"]
|
||||
to_state = event.data["new_state"]
|
||||
|
||||
# Ignore unavailable states
|
||||
if to_state is None or to_state.state == STATE_UNAVAILABLE:
|
||||
return
|
||||
|
||||
# Trigger when pausing
|
||||
if (
|
||||
from_state is not None
|
||||
and from_state.state != STATE_PAUSED
|
||||
and to_state.state == STATE_PAUSED
|
||||
):
|
||||
run_action(
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
"from_state": from_state,
|
||||
"to_state": to_state,
|
||||
},
|
||||
f"media player {entity_id} paused",
|
||||
event.context,
|
||||
)
|
||||
|
||||
def entity_filter(entities: set[str]) -> set[str]:
|
||||
"""Filter entities of this domain."""
|
||||
return {
|
||||
entity_id
|
||||
for entity_id in entities
|
||||
if split_entity_id(entity_id)[0] == DOMAIN
|
||||
}
|
||||
|
||||
return async_track_target_selector_state_change_event(
|
||||
self._hass, self._target, state_change_listener, entity_filter
|
||||
)
|
||||
|
||||
|
||||
TRIGGERS: dict[str, type[Trigger]] = {
|
||||
"turns_on": MediaPlayerTurnsOnTrigger,
|
||||
"turns_off": MediaPlayerTurnsOffTrigger,
|
||||
"playing": MediaPlayerPlayingTrigger,
|
||||
"paused": MediaPlayerPausedTrigger,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,3 +21,8 @@ playing:
|
||||
multiple: true
|
||||
custom_value: true
|
||||
options: []
|
||||
|
||||
paused:
|
||||
target:
|
||||
entity:
|
||||
domain: media_player
|
||||
|
||||
@@ -208,3 +208,46 @@ async def test_playing_trigger_with_media_content_type_filter(
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 0
|
||||
|
||||
|
||||
async def test_paused_trigger(
|
||||
hass: HomeAssistant, service_calls: list[ServiceCall]
|
||||
) -> None:
|
||||
"""Test that the paused trigger fires when a media player pauses."""
|
||||
entity_id = "media_player.test"
|
||||
await async_setup_component(hass, "media_player", {})
|
||||
|
||||
# Set initial state to playing
|
||||
hass.states.async_set(entity_id, STATE_PLAYING)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"triggers": {
|
||||
"trigger": "media_player.paused",
|
||||
"target": {CONF_ENTITY_ID: entity_id},
|
||||
},
|
||||
"actions": {
|
||||
"action": "test.automation",
|
||||
"data": {
|
||||
CONF_ENTITY_ID: "{{ trigger.entity_id }}",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Pause - should trigger
|
||||
hass.states.async_set(entity_id, STATE_PAUSED)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 1
|
||||
assert service_calls[0].data[CONF_ENTITY_ID] == entity_id
|
||||
service_calls.clear()
|
||||
|
||||
# Already paused - should not trigger
|
||||
hass.states.async_set(entity_id, STATE_PAUSED)
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 0
|
||||
|
||||
Reference in New Issue
Block a user