Add changed states device trigger to media_player entity (#64304)

This commit is contained in:
Erik Montnemery 2022-01-17 17:27:56 +01:00 committed by GitHub
parent 513d6cc467
commit ff9bea9fa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 32 deletions

View File

@ -9,7 +9,10 @@ from homeassistant.components.automation import (
AutomationActionType, AutomationActionType,
AutomationTriggerInfo, AutomationTriggerInfo,
) )
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA from homeassistant.components.device_automation import (
DEVICE_TRIGGER_BASE_SCHEMA,
entity,
)
from homeassistant.components.homeassistant.triggers import state as state_trigger from homeassistant.components.homeassistant.triggers import state as state_trigger
from homeassistant.const import ( from homeassistant.const import (
CONF_DEVICE_ID, CONF_DEVICE_ID,
@ -32,7 +35,7 @@ from .const import DOMAIN
TRIGGER_TYPES = {"turned_on", "turned_off", "idle", "paused", "playing"} TRIGGER_TYPES = {"turned_on", "turned_off", "idle", "paused", "playing"}
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend( MEDIA_PLAYER_TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
{ {
vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES), vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
@ -40,13 +43,21 @@ TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
} }
) )
TRIGGER_SCHEMA = vol.All(
vol.Any(
MEDIA_PLAYER_TRIGGER_SCHEMA,
entity.TRIGGER_SCHEMA,
),
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
)
async def async_get_triggers( async def async_get_triggers(
hass: HomeAssistant, device_id: str hass: HomeAssistant, device_id: str
) -> list[dict[str, Any]]: ) -> list[dict[str, Any]]:
"""List device triggers for Media player entities.""" """List device triggers for Media player entities."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
triggers = [] triggers = await entity.async_get_triggers(hass, device_id, DOMAIN)
# Get all the integration entities for this device # Get all the integration entities for this device
for entry in entity_registry.async_entries_for_device(registry, device_id): for entry in entity_registry.async_entries_for_device(registry, device_id):
@ -72,6 +83,8 @@ async def async_get_trigger_capabilities(
hass: HomeAssistant, config: ConfigType hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]: ) -> dict[str, vol.Schema]:
"""List trigger capabilities.""" """List trigger capabilities."""
if config[CONF_TYPE] not in TRIGGER_TYPES:
return await entity.async_get_trigger_capabilities(hass, config)
return { return {
"extra_fields": vol.Schema( "extra_fields": vol.Schema(
{vol.Optional(CONF_FOR): cv.positive_time_period_dict} {vol.Optional(CONF_FOR): cv.positive_time_period_dict}
@ -86,6 +99,8 @@ async def async_attach_trigger(
automation_info: AutomationTriggerInfo, automation_info: AutomationTriggerInfo,
) -> CALLBACK_TYPE: ) -> CALLBACK_TYPE:
"""Attach a trigger.""" """Attach a trigger."""
if config[CONF_TYPE] not in TRIGGER_TYPES:
return await entity.async_attach_trigger(hass, config, action, automation_info)
if config[CONF_TYPE] == "turned_on": if config[CONF_TYPE] == "turned_on":
to_state = STATE_ON to_state = STATE_ON
elif config[CONF_TYPE] == "turned_off": elif config[CONF_TYPE] == "turned_off":

View File

@ -13,7 +13,8 @@
"turned_off": "{entity_name} turned off", "turned_off": "{entity_name} turned off",
"idle": "{entity_name} becomes idle", "idle": "{entity_name} becomes idle",
"paused": "{entity_name} is paused", "paused": "{entity_name} is paused",
"playing": "{entity_name} starts playing" "playing": "{entity_name} starts playing",
"changed_states": "{entity_name} changed states"
} }
}, },
"state": { "state": {

View File

@ -58,7 +58,14 @@ async def test_get_triggers(hass, device_reg, entity_reg):
) )
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
trigger_types = {"turned_on", "turned_off", "idle", "paused", "playing"} trigger_types = {
"turned_on",
"turned_off",
"idle",
"paused",
"playing",
"changed_states",
}
expected_triggers = [ expected_triggers = [
{ {
"platform": "device", "platform": "device",
@ -88,7 +95,7 @@ async def test_get_trigger_capabilities(hass, device_reg, entity_reg):
triggers = await async_get_device_automations( triggers = await async_get_device_automations(
hass, DeviceAutomationType.TRIGGER, device_entry.id hass, DeviceAutomationType.TRIGGER, device_entry.id
) )
assert len(triggers) == 5 assert len(triggers) == 6
for trigger in triggers: for trigger in triggers:
capabilities = await async_get_device_automation_capabilities( capabilities = await async_get_device_automation_capabilities(
hass, DeviceAutomationType.TRIGGER, trigger hass, DeviceAutomationType.TRIGGER, trigger
@ -109,7 +116,14 @@ async def test_if_fires_on_state_change(hass, calls):
"{{{{ trigger.entity_id}}}} - {{{{ trigger.from_state.state}}}} - " "{{{{ trigger.entity_id}}}} - {{{{ trigger.from_state.state}}}} - "
"{{{{ trigger.to_state.state}}}} - {{{{ trigger.for }}}}" "{{{{ trigger.to_state.state}}}} - {{{{ trigger.for }}}}"
) )
trigger_types = {"turned_on", "turned_off", "idle", "paused", "playing"} trigger_types = {
"turned_on",
"turned_off",
"idle",
"paused",
"playing",
"changed_states",
}
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -137,47 +151,47 @@ async def test_if_fires_on_state_change(hass, calls):
# Fake that the entity is turning on. # Fake that the entity is turning on.
hass.states.async_set("media_player.entity", STATE_ON) hass.states.async_set("media_player.entity", STATE_ON)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 1 assert len(calls) == 2
assert ( assert {calls[0].data["some"], calls[1].data["some"]} == {
calls[0].data["some"] "turned_on - device - media_player.entity - off - on - None",
== "turned_on - device - media_player.entity - off - on - None" "changed_states - device - media_player.entity - off - on - None",
) }
# Fake that the entity is turning off. # Fake that the entity is turning off.
hass.states.async_set("media_player.entity", STATE_OFF) hass.states.async_set("media_player.entity", STATE_OFF)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 2 assert len(calls) == 4
assert ( assert {calls[2].data["some"], calls[3].data["some"]} == {
calls[1].data["some"] "turned_off - device - media_player.entity - on - off - None",
== "turned_off - device - media_player.entity - on - off - None" "changed_states - device - media_player.entity - on - off - None",
) }
# Fake that the entity becomes idle. # Fake that the entity becomes idle.
hass.states.async_set("media_player.entity", STATE_IDLE) hass.states.async_set("media_player.entity", STATE_IDLE)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 3 assert len(calls) == 6
assert ( assert {calls[4].data["some"], calls[5].data["some"]} == {
calls[2].data["some"] "idle - device - media_player.entity - off - idle - None",
== "idle - device - media_player.entity - off - idle - None" "changed_states - device - media_player.entity - off - idle - None",
) }
# Fake that the entity starts playing. # Fake that the entity starts playing.
hass.states.async_set("media_player.entity", STATE_PLAYING) hass.states.async_set("media_player.entity", STATE_PLAYING)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 4 assert len(calls) == 8
assert ( assert {calls[6].data["some"], calls[7].data["some"]} == {
calls[3].data["some"] "playing - device - media_player.entity - idle - playing - None",
== "playing - device - media_player.entity - idle - playing - None" "changed_states - device - media_player.entity - idle - playing - None",
) }
# Fake that the entity is paused. # Fake that the entity is paused.
hass.states.async_set("media_player.entity", STATE_PAUSED) hass.states.async_set("media_player.entity", STATE_PAUSED)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 5 assert len(calls) == 10
assert ( assert {calls[8].data["some"], calls[9].data["some"]} == {
calls[4].data["some"] "paused - device - media_player.entity - playing - paused - None",
== "paused - device - media_player.entity - playing - paused - None" "changed_states - device - media_player.entity - playing - paused - None",
) }
async def test_if_fires_on_state_change_with_for(hass, calls): async def test_if_fires_on_state_change_with_for(hass, calls):