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(
{
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.Optional(CONF_FOR): cv.positive_time_period_dict,
}
@ -72,7 +72,7 @@ async def async_get_triggers(
CONF_PLATFORM: "device",
CONF_DEVICE_ID: device_id,
CONF_DOMAIN: DOMAIN,
CONF_ENTITY_ID: entry.entity_id,
CONF_ENTITY_ID: entry.id,
}
triggers += [

View File

@ -470,13 +470,15 @@ class EntityRegistry:
return entity_id in self.entities
@callback
def async_get(self, entity_id: str) -> RegistryEntry | None:
"""Get EntityEntry for an entity_id.
def async_get(self, entity_id_or_uuid: str) -> RegistryEntry | None:
"""Get EntityEntry for an entity_id or entity entry id.
We retrieve the RegistryEntry from the underlying dict to avoid
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
def async_get_entity_id(

View File

@ -96,7 +96,7 @@ async def test_get_triggers(
config_entry_id=config_entry.entry_id,
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,
"test",
"5678",
@ -105,7 +105,7 @@ async def test_get_triggers(
)
if set_state:
hass.states.async_set(
"alarm_control_panel.test_5678",
entry.entity_id,
"attributes",
{"supported_features": features_state},
)
@ -117,7 +117,7 @@ async def test_get_triggers(
"domain": DOMAIN,
"type": trigger,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"entity_id": entry.id,
"metadata": {"secondary": False},
}
for trigger in expected_trigger_types
@ -151,7 +151,7 @@ async def test_get_triggers_hidden_auxiliary(
config_entry_id=config_entry.entry_id,
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,
"test",
"5678",
@ -165,7 +165,7 @@ async def test_get_triggers_hidden_auxiliary(
"domain": DOMAIN,
"type": trigger,
"device_id": device_entry.id,
"entity_id": f"{DOMAIN}.test_5678",
"entity_id": entry.id,
"metadata": {"secondary": True},
}
for trigger in ["triggered", "disarmed", "arming"]
@ -211,10 +211,12 @@ async def test_get_trigger_capabilities(
async def test_if_fires_on_state_change(
hass: HomeAssistant, calls: list[ServiceCall]
) -> None:
hass: HomeAssistant, entity_registry: er.EntityRegistry, calls: list[ServiceCall]
):
"""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(
hass,
@ -226,7 +228,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "triggered",
},
"action": {
@ -248,7 +250,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "disarmed",
},
"action": {
@ -270,7 +272,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "armed_home",
},
"action": {
@ -292,7 +294,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "armed_away",
},
"action": {
@ -314,7 +316,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "armed_night",
},
"action": {
@ -336,7 +338,7 @@ async def test_if_fires_on_state_change(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": "alarm_control_panel.entity",
"entity_id": entry.id,
"type": "armed_vacation",
},
"action": {
@ -358,72 +360,67 @@ async def test_if_fires_on_state_change(
)
# 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()
assert len(calls) == 1
assert (
calls[0].data["some"]
== "triggered - device - alarm_control_panel.entity - pending - triggered -"
" None"
== f"triggered - device - {entry.entity_id} - pending - triggered - None"
)
# 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()
assert len(calls) == 2
assert (
calls[1].data["some"]
== "disarmed - device - alarm_control_panel.entity - triggered - disarmed -"
" None"
== f"disarmed - device - {entry.entity_id} - triggered - disarmed - None"
)
# 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()
assert len(calls) == 3
assert (
calls[2].data["some"]
== "armed_home - device - alarm_control_panel.entity - disarmed - armed_home -"
" None"
== f"armed_home - device - {entry.entity_id} - disarmed - armed_home - None"
)
# 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()
assert len(calls) == 4
assert (
calls[3].data["some"]
== "armed_away - device - alarm_control_panel.entity - armed_home - armed_away"
" - None"
== f"armed_away - device - {entry.entity_id} - armed_home - armed_away - None"
)
# 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()
assert len(calls) == 5
assert (
calls[4].data["some"]
== "armed_night - device - alarm_control_panel.entity - armed_away -"
" armed_night - None"
== f"armed_night - device - {entry.entity_id} - armed_away - armed_night - None"
)
# 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()
assert len(calls) == 6
assert (
calls[5].data["some"]
== "armed_vacation - device - alarm_control_panel.entity - armed_night -"
" armed_vacation - None"
== f"armed_vacation - device - {entry.entity_id} - armed_night - armed_vacation - None"
)
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:
"""Test for triggers firing with delay."""
entity_id = f"{DOMAIN}.entity"
hass.states.async_set(entity_id, STATE_ALARM_DISARMED)
entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678")
hass.states.async_set(entry.entity_id, STATE_ALARM_DISARMED)
assert await async_setup_component(
hass,
@ -435,7 +432,7 @@ async def test_if_fires_on_state_change_with_for(
"platform": "device",
"domain": DOMAIN,
"device_id": "",
"entity_id": entity_id,
"entity_id": entry.id,
"type": "triggered",
"for": {"seconds": 5},
},
@ -459,10 +456,9 @@ async def test_if_fires_on_state_change_with_for(
},
)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
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()
assert len(calls) == 0
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()
assert (
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
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(
hass: HomeAssistant, entity_registry: er.EntityRegistry, update_events
) -> None: