Teach numeric state trigger about entity registry ids (#60835)

This commit is contained in:
Erik Montnemery 2021-12-02 18:45:40 +01:00 committed by GitHub
parent f46055de99
commit 36734972f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 17 deletions

View file

@ -159,7 +159,9 @@ async def async_attach_trigger(
if CONF_FOR in config:
numeric_state_config[CONF_FOR] = config[CONF_FOR]
numeric_state_config = numeric_state_trigger.TRIGGER_SCHEMA(numeric_state_config)
numeric_state_config = await numeric_state_trigger.async_validate_trigger_config(
hass, numeric_state_config
)
return await numeric_state_trigger.async_attach_trigger(
hass, numeric_state_config, action, automation_info, platform_type="device"
)

View file

@ -192,7 +192,9 @@ async def async_attach_trigger(
CONF_ABOVE: min_pos,
CONF_VALUE_TEMPLATE: value_template,
}
numeric_state_config = numeric_state_trigger.TRIGGER_SCHEMA(numeric_state_config)
numeric_state_config = await numeric_state_trigger.async_validate_trigger_config(
hass, numeric_state_config
)
return await numeric_state_trigger.async_attach_trigger(
hass, numeric_state_config, action, automation_info, platform_type="device"
)

View file

@ -13,12 +13,18 @@ from homeassistant.const import (
CONF_PLATFORM,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import CALLBACK_TYPE, HassJob, callback
from homeassistant.helpers import condition, config_validation as cv, template
from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback
from homeassistant.helpers import (
condition,
config_validation as cv,
entity_registry as er,
template,
)
from homeassistant.helpers.event import (
async_track_same_state,
async_track_state_change_event,
)
from homeassistant.helpers.typing import ConfigType
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
# mypy: no-check-untyped-defs
@ -43,11 +49,11 @@ def validate_above_below(value):
return value
TRIGGER_SCHEMA = vol.All(
_TRIGGER_SCHEMA = vol.All(
cv.TRIGGER_BASE_SCHEMA.extend(
{
vol.Required(CONF_PLATFORM): "numeric_state",
vol.Required(CONF_ENTITY_ID): cv.entity_ids,
vol.Required(CONF_ENTITY_ID): cv.entity_ids_or_uuids,
vol.Optional(CONF_BELOW): cv.NUMERIC_STATE_THRESHOLD_SCHEMA,
vol.Optional(CONF_ABOVE): cv.NUMERIC_STATE_THRESHOLD_SCHEMA,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
@ -62,6 +68,18 @@ TRIGGER_SCHEMA = vol.All(
_LOGGER = logging.getLogger(__name__)
async def async_validate_trigger_config(
hass: HomeAssistant, config: ConfigType
) -> ConfigType:
"""Validate trigger config."""
config = _TRIGGER_SCHEMA(config)
registry = er.async_get(hass)
config[CONF_ENTITY_ID] = er.async_resolve_entity_ids(
registry, cv.entity_ids_or_uuids(config[CONF_ENTITY_ID])
)
return config
async def async_attach_trigger(
hass, config, action, automation_info, *, platform_type="numeric_state"
) -> CALLBACK_TYPE:

View file

@ -100,8 +100,10 @@ async def async_attach_trigger(
if CONF_FOR in config:
numeric_state_config[CONF_FOR] = config[CONF_FOR]
numeric_state_config = numeric_state_trigger.TRIGGER_SCHEMA(
numeric_state_config
numeric_state_config = (
await numeric_state_trigger.async_validate_trigger_config(
hass, numeric_state_config
)
)
return await numeric_state_trigger.async_attach_trigger(
hass, numeric_state_config, action, automation_info, platform_type="device"

View file

@ -162,7 +162,9 @@ async def async_attach_trigger(hass, config, action, automation_info):
if CONF_FOR in config:
numeric_state_config[CONF_FOR] = config[CONF_FOR]
numeric_state_config = numeric_state_trigger.TRIGGER_SCHEMA(numeric_state_config)
numeric_state_config = await numeric_state_trigger.async_validate_trigger_config(
hass, numeric_state_config
)
return await numeric_state_trigger.async_attach_trigger(
hass, numeric_state_config, action, automation_info, platform_type="device"
)

View file

@ -12,6 +12,7 @@ from homeassistant.components.homeassistant.triggers import (
)
from homeassistant.const import ATTR_ENTITY_ID, ENTITY_MATCH_ALL, SERVICE_TURN_OFF
from homeassistant.core import Context
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
@ -126,6 +127,59 @@ async def test_if_fires_on_entity_change_below(hass, calls, below):
assert calls[0].data["id"] == 0
@pytest.mark.parametrize(
"below", (10, "input_number.value_10", "number.value_10", "sensor.value_10")
)
async def test_if_fires_on_entity_change_below_uuid(hass, calls, below):
"""Test the firing with changed entity specified by registry entry id."""
registry = er.async_get(hass)
entry = registry.async_get_or_create(
"test", "hue", "1234", suggested_object_id="entity"
)
assert entry.entity_id == "test.entity"
hass.states.async_set("test.entity", 11)
await hass.async_block_till_done()
context = Context()
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"trigger": {
"platform": "numeric_state",
"entity_id": entry.id,
"below": below,
},
"action": {
"service": "test.automation",
"data_template": {"id": "{{ trigger.id}}"},
},
}
},
)
# 9 is below 10
hass.states.async_set("test.entity", 9, context=context)
await hass.async_block_till_done()
assert len(calls) == 1
assert calls[0].context.parent_id == context.id
# Set above 12 so the automation will fire again
hass.states.async_set("test.entity", 12)
await hass.services.async_call(
automation.DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: ENTITY_MATCH_ALL},
blocking=True,
)
hass.states.async_set("test.entity", 9)
await hass.async_block_till_done()
assert len(calls) == 1
assert calls[0].data["id"] == 0
@pytest.mark.parametrize(
"below", (10, "input_number.value_10", "number.value_10", "sensor.value_10")
)
@ -1644,31 +1698,33 @@ async def test_if_fires_on_entities_change_overlap_for_template(
assert calls[1].data["some"] == "test.entity_2 - 0:00:10"
def test_below_above():
async def test_below_above(hass):
"""Test above cannot be above below."""
with pytest.raises(vol.Invalid):
numeric_state_trigger.TRIGGER_SCHEMA(
{"platform": "numeric_state", "above": 1200, "below": 1000}
await numeric_state_trigger.async_validate_trigger_config(
hass, {"platform": "numeric_state", "above": 1200, "below": 1000}
)
def test_schema_unacceptable_entities():
async def test_schema_unacceptable_entities(hass):
"""Test input_number, number & sensor only is accepted for above/below."""
with pytest.raises(vol.Invalid):
numeric_state_trigger.TRIGGER_SCHEMA(
await numeric_state_trigger.async_validate_trigger_config(
hass,
{
"platform": "numeric_state",
"above": "input_datetime.some_input",
"below": 1000,
}
},
)
with pytest.raises(vol.Invalid):
numeric_state_trigger.TRIGGER_SCHEMA(
await numeric_state_trigger.async_validate_trigger_config(
hass,
{
"platform": "numeric_state",
"below": "input_datetime.some_input",
"above": 1200,
}
},
)