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

pull/64314/head
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,
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.const import (
CONF_DEVICE_ID,
@ -32,7 +35,7 @@ from .const import DOMAIN
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_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(
hass: HomeAssistant, device_id: str
) -> list[dict[str, Any]]:
"""List device triggers for Media player entities."""
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
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
) -> dict[str, vol.Schema]:
"""List trigger capabilities."""
if config[CONF_TYPE] not in TRIGGER_TYPES:
return await entity.async_get_trigger_capabilities(hass, config)
return {
"extra_fields": vol.Schema(
{vol.Optional(CONF_FOR): cv.positive_time_period_dict}
@ -86,6 +99,8 @@ async def async_attach_trigger(
automation_info: AutomationTriggerInfo,
) -> CALLBACK_TYPE:
"""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":
to_state = STATE_ON
elif config[CONF_TYPE] == "turned_off":

View File

@ -13,7 +13,8 @@
"turned_off": "{entity_name} turned off",
"idle": "{entity_name} becomes idle",
"paused": "{entity_name} is paused",
"playing": "{entity_name} starts playing"
"playing": "{entity_name} starts playing",
"changed_states": "{entity_name} changed states"
}
},
"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)
trigger_types = {"turned_on", "turned_off", "idle", "paused", "playing"}
trigger_types = {
"turned_on",
"turned_off",
"idle",
"paused",
"playing",
"changed_states",
}
expected_triggers = [
{
"platform": "device",
@ -88,7 +95,7 @@ async def test_get_trigger_capabilities(hass, device_reg, entity_reg):
triggers = await async_get_device_automations(
hass, DeviceAutomationType.TRIGGER, device_entry.id
)
assert len(triggers) == 5
assert len(triggers) == 6
for trigger in triggers:
capabilities = await async_get_device_automation_capabilities(
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.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(
hass,
@ -137,47 +151,47 @@ async def test_if_fires_on_state_change(hass, calls):
# Fake that the entity is turning on.
hass.states.async_set("media_player.entity", STATE_ON)
await hass.async_block_till_done()
assert len(calls) == 1
assert (
calls[0].data["some"]
== "turned_on - device - media_player.entity - off - on - None"
)
assert len(calls) == 2
assert {calls[0].data["some"], calls[1].data["some"]} == {
"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.
hass.states.async_set("media_player.entity", STATE_OFF)
await hass.async_block_till_done()
assert len(calls) == 2
assert (
calls[1].data["some"]
== "turned_off - device - media_player.entity - on - off - None"
)
assert len(calls) == 4
assert {calls[2].data["some"], calls[3].data["some"]} == {
"turned_off - device - media_player.entity - on - off - None",
"changed_states - device - media_player.entity - on - off - None",
}
# Fake that the entity becomes idle.
hass.states.async_set("media_player.entity", STATE_IDLE)
await hass.async_block_till_done()
assert len(calls) == 3
assert (
calls[2].data["some"]
== "idle - device - media_player.entity - off - idle - None"
)
assert len(calls) == 6
assert {calls[4].data["some"], calls[5].data["some"]} == {
"idle - device - media_player.entity - off - idle - None",
"changed_states - device - media_player.entity - off - idle - None",
}
# Fake that the entity starts playing.
hass.states.async_set("media_player.entity", STATE_PLAYING)
await hass.async_block_till_done()
assert len(calls) == 4
assert (
calls[3].data["some"]
== "playing - device - media_player.entity - idle - playing - None"
)
assert len(calls) == 8
assert {calls[6].data["some"], calls[7].data["some"]} == {
"playing - device - media_player.entity - idle - playing - None",
"changed_states - device - media_player.entity - idle - playing - None",
}
# Fake that the entity is paused.
hass.states.async_set("media_player.entity", STATE_PAUSED)
await hass.async_block_till_done()
assert len(calls) == 5
assert (
calls[4].data["some"]
== "paused - device - media_player.entity - playing - paused - None"
)
assert len(calls) == 10
assert {calls[8].data["some"], calls[9].data["some"]} == {
"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):