Teach alarm_control_panel device trigger about entity registry ids (#60977)

* Teach alarm_control_panel device trigger about entity registry ids

* Lint code

* Address review comment
This commit is contained in:
Erik Montnemery 2023-06-20 14:27:31 +02:00 committed by GitHub
parent 2bc5198390
commit 4a8adae146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 44 deletions

View File

@ -46,7 +46,7 @@ TRIGGER_TYPES: Final[set[str]] = BASIC_TRIGGER_TYPES | {
TRIGGER_SCHEMA: Final = DEVICE_TRIGGER_BASE_SCHEMA.extend( TRIGGER_SCHEMA: Final = DEVICE_TRIGGER_BASE_SCHEMA.extend(
{ {
vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES), vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
vol.Optional(CONF_FOR): cv.positive_time_period_dict, vol.Optional(CONF_FOR): cv.positive_time_period_dict,
} }
@ -72,7 +72,7 @@ async def async_get_triggers(
CONF_PLATFORM: "device", CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id, CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN, CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id, CONF_ENTITY_ID: entry.id,
} }
triggers += [ triggers += [

View File

@ -470,13 +470,15 @@ class EntityRegistry:
return entity_id in self.entities return entity_id in self.entities
@callback @callback
def async_get(self, entity_id: str) -> RegistryEntry | None: def async_get(self, entity_id_or_uuid: str) -> RegistryEntry | None:
"""Get EntityEntry for an entity_id. """Get EntityEntry for an entity_id or entity entry id.
We retrieve the RegistryEntry from the underlying dict to avoid We retrieve the RegistryEntry from the underlying dict to avoid
the overhead of the UserDict __getitem__. the overhead of the UserDict __getitem__.
""" """
return self._entities_data.get(entity_id) return self._entities_data.get(entity_id_or_uuid) or self.entities.get_entry(
entity_id_or_uuid
)
@callback @callback
def async_get_entity_id( def async_get_entity_id(

View File

@ -96,7 +96,7 @@ async def test_get_triggers(
config_entry_id=config_entry.entry_id, config_entry_id=config_entry.entry_id,
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
) )
entity_registry.async_get_or_create( entry = entity_registry.async_get_or_create(
DOMAIN, DOMAIN,
"test", "test",
"5678", "5678",
@ -105,7 +105,7 @@ async def test_get_triggers(
) )
if set_state: if set_state:
hass.states.async_set( hass.states.async_set(
"alarm_control_panel.test_5678", entry.entity_id,
"attributes", "attributes",
{"supported_features": features_state}, {"supported_features": features_state},
) )
@ -117,7 +117,7 @@ async def test_get_triggers(
"domain": DOMAIN, "domain": DOMAIN,
"type": trigger, "type": trigger,
"device_id": device_entry.id, "device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678", "entity_id": entry.id,
"metadata": {"secondary": False}, "metadata": {"secondary": False},
} }
for trigger in expected_trigger_types for trigger in expected_trigger_types
@ -151,7 +151,7 @@ async def test_get_triggers_hidden_auxiliary(
config_entry_id=config_entry.entry_id, config_entry_id=config_entry.entry_id,
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
) )
entity_registry.async_get_or_create( entry = entity_registry.async_get_or_create(
DOMAIN, DOMAIN,
"test", "test",
"5678", "5678",
@ -165,7 +165,7 @@ async def test_get_triggers_hidden_auxiliary(
"domain": DOMAIN, "domain": DOMAIN,
"type": trigger, "type": trigger,
"device_id": device_entry.id, "device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678", "entity_id": entry.id,
"metadata": {"secondary": True}, "metadata": {"secondary": True},
} }
for trigger in ["triggered", "disarmed", "arming"] for trigger in ["triggered", "disarmed", "arming"]
@ -211,10 +211,12 @@ async def test_get_trigger_capabilities(
async def test_if_fires_on_state_change( async def test_if_fires_on_state_change(
hass: HomeAssistant, calls: list[ServiceCall] hass: HomeAssistant, entity_registry: er.EntityRegistry, calls: list[ServiceCall]
) -> None: ):
"""Test for turn_on and turn_off triggers firing.""" """Test for turn_on and turn_off triggers firing."""
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_PENDING) entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678")
hass.states.async_set(entry.entity_id, STATE_ALARM_PENDING)
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -226,7 +228,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "triggered", "type": "triggered",
}, },
"action": { "action": {
@ -248,7 +250,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "disarmed", "type": "disarmed",
}, },
"action": { "action": {
@ -270,7 +272,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "armed_home", "type": "armed_home",
}, },
"action": { "action": {
@ -292,7 +294,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "armed_away", "type": "armed_away",
}, },
"action": { "action": {
@ -314,7 +316,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "armed_night", "type": "armed_night",
}, },
"action": { "action": {
@ -336,7 +338,7 @@ async def test_if_fires_on_state_change(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": "alarm_control_panel.entity", "entity_id": entry.id,
"type": "armed_vacation", "type": "armed_vacation",
}, },
"action": { "action": {
@ -358,72 +360,67 @@ async def test_if_fires_on_state_change(
) )
# Fake that the entity is triggered. # Fake that the entity is triggered.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_TRIGGERED) hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 1 assert len(calls) == 1
assert ( assert (
calls[0].data["some"] calls[0].data["some"]
== "triggered - device - alarm_control_panel.entity - pending - triggered -" == f"triggered - device - {entry.entity_id} - pending - triggered - None"
" None"
) )
# Fake that the entity is disarmed. # Fake that the entity is disarmed.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_DISARMED) hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 2 assert len(calls) == 2
assert ( assert (
calls[1].data["some"] calls[1].data["some"]
== "disarmed - device - alarm_control_panel.entity - triggered - disarmed -" == f"disarmed - device - {entry.entity_id} - triggered - disarmed - None"
" None"
) )
# Fake that the entity is armed home. # Fake that the entity is armed home.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_ARMED_HOME) hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_HOME)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 3 assert len(calls) == 3
assert ( assert (
calls[2].data["some"] calls[2].data["some"]
== "armed_home - device - alarm_control_panel.entity - disarmed - armed_home -" == f"armed_home - device - {entry.entity_id} - disarmed - armed_home - None"
" None"
) )
# Fake that the entity is armed away. # Fake that the entity is armed away.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_ARMED_AWAY) hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_AWAY)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 4 assert len(calls) == 4
assert ( assert (
calls[3].data["some"] calls[3].data["some"]
== "armed_away - device - alarm_control_panel.entity - armed_home - armed_away" == f"armed_away - device - {entry.entity_id} - armed_home - armed_away - None"
" - None"
) )
# Fake that the entity is armed night. # Fake that the entity is armed night.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_ARMED_NIGHT) hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_NIGHT)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 5 assert len(calls) == 5
assert ( assert (
calls[4].data["some"] calls[4].data["some"]
== "armed_night - device - alarm_control_panel.entity - armed_away -" == f"armed_night - device - {entry.entity_id} - armed_away - armed_night - None"
" armed_night - None"
) )
# Fake that the entity is armed vacation. # Fake that the entity is armed vacation.
hass.states.async_set("alarm_control_panel.entity", STATE_ALARM_ARMED_VACATION) hass.states.async_set(entry.entity_id, STATE_ALARM_ARMED_VACATION)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 6 assert len(calls) == 6
assert ( assert (
calls[5].data["some"] calls[5].data["some"]
== "armed_vacation - device - alarm_control_panel.entity - armed_night -" == f"armed_vacation - device - {entry.entity_id} - armed_night - armed_vacation - None"
" armed_vacation - None"
) )
async def test_if_fires_on_state_change_with_for( async def test_if_fires_on_state_change_with_for(
hass: HomeAssistant, calls: list[ServiceCall] hass: HomeAssistant, entity_registry: er.EntityRegistry, calls: list[ServiceCall]
) -> None: ) -> None:
"""Test for triggers firing with delay.""" """Test for triggers firing with delay."""
entity_id = f"{DOMAIN}.entity" entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678")
hass.states.async_set(entity_id, STATE_ALARM_DISARMED)
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
assert await async_setup_component( assert await async_setup_component(
hass, hass,
@ -435,7 +432,7 @@ async def test_if_fires_on_state_change_with_for(
"platform": "device", "platform": "device",
"domain": DOMAIN, "domain": DOMAIN,
"device_id": "", "device_id": "",
"entity_id": entity_id, "entity_id": entry.id,
"type": "triggered", "type": "triggered",
"for": {"seconds": 5}, "for": {"seconds": 5},
}, },
@ -459,10 +456,9 @@ async def test_if_fires_on_state_change_with_for(
}, },
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
assert len(calls) == 0 assert len(calls) == 0
hass.states.async_set(entity_id, STATE_ALARM_TRIGGERED) hass.states.async_set(entry.entity_id, STATE_ALARM_TRIGGERED)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 0 assert len(calls) == 0
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
@ -471,5 +467,5 @@ async def test_if_fires_on_state_change_with_for(
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert (
calls[0].data["some"] calls[0].data["some"]
== f"turn_off device - {entity_id} - disarmed - triggered - 0:00:05" == f"turn_off device - {entry.entity_id} - disarmed - triggered - 0:00:05"
) )

View File

@ -34,6 +34,16 @@ def update_events(hass):
return events return events
async def test_get(hass: HomeAssistant, entity_registry: er.EntityRegistry):
"""Test we can get an item."""
entry = entity_registry.async_get_or_create("light", "hue", "1234")
assert entity_registry.async_get(entry.entity_id) is entry
assert entity_registry.async_get(entry.id) is entry
assert entity_registry.async_get("blah") is None
assert entity_registry.async_get("blah.blah") is None
async def test_get_or_create_returns_same_entry( async def test_get_or_create_returns_same_entry(
hass: HomeAssistant, entity_registry: er.EntityRegistry, update_events hass: HomeAssistant, entity_registry: er.EntityRegistry, update_events
) -> None: ) -> None: