Teach numeric state trigger about entity registry ids (#60835)
This commit is contained in:
parent
f46055de99
commit
36734972f0
6 changed files with 99 additions and 17 deletions
|
@ -159,7 +159,9 @@ async def async_attach_trigger(
|
||||||
if CONF_FOR in config:
|
if CONF_FOR in config:
|
||||||
numeric_state_config[CONF_FOR] = config[CONF_FOR]
|
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(
|
return await numeric_state_trigger.async_attach_trigger(
|
||||||
hass, numeric_state_config, action, automation_info, platform_type="device"
|
hass, numeric_state_config, action, automation_info, platform_type="device"
|
||||||
)
|
)
|
||||||
|
|
|
@ -192,7 +192,9 @@ async def async_attach_trigger(
|
||||||
CONF_ABOVE: min_pos,
|
CONF_ABOVE: min_pos,
|
||||||
CONF_VALUE_TEMPLATE: value_template,
|
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(
|
return await numeric_state_trigger.async_attach_trigger(
|
||||||
hass, numeric_state_config, action, automation_info, platform_type="device"
|
hass, numeric_state_config, action, automation_info, platform_type="device"
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,12 +13,18 @@ from homeassistant.const import (
|
||||||
CONF_PLATFORM,
|
CONF_PLATFORM,
|
||||||
CONF_VALUE_TEMPLATE,
|
CONF_VALUE_TEMPLATE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import CALLBACK_TYPE, HassJob, callback
|
from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback
|
||||||
from homeassistant.helpers import condition, config_validation as cv, template
|
from homeassistant.helpers import (
|
||||||
|
condition,
|
||||||
|
config_validation as cv,
|
||||||
|
entity_registry as er,
|
||||||
|
template,
|
||||||
|
)
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_same_state,
|
async_track_same_state,
|
||||||
async_track_state_change_event,
|
async_track_state_change_event,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
|
||||||
# mypy: no-check-untyped-defs
|
# mypy: no-check-untyped-defs
|
||||||
|
@ -43,11 +49,11 @@ def validate_above_below(value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
TRIGGER_SCHEMA = vol.All(
|
_TRIGGER_SCHEMA = vol.All(
|
||||||
cv.TRIGGER_BASE_SCHEMA.extend(
|
cv.TRIGGER_BASE_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_PLATFORM): "numeric_state",
|
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_BELOW): cv.NUMERIC_STATE_THRESHOLD_SCHEMA,
|
||||||
vol.Optional(CONF_ABOVE): cv.NUMERIC_STATE_THRESHOLD_SCHEMA,
|
vol.Optional(CONF_ABOVE): cv.NUMERIC_STATE_THRESHOLD_SCHEMA,
|
||||||
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
|
@ -62,6 +68,18 @@ TRIGGER_SCHEMA = vol.All(
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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(
|
async def async_attach_trigger(
|
||||||
hass, config, action, automation_info, *, platform_type="numeric_state"
|
hass, config, action, automation_info, *, platform_type="numeric_state"
|
||||||
) -> CALLBACK_TYPE:
|
) -> CALLBACK_TYPE:
|
||||||
|
|
|
@ -100,8 +100,10 @@ async def async_attach_trigger(
|
||||||
if CONF_FOR in config:
|
if CONF_FOR in config:
|
||||||
numeric_state_config[CONF_FOR] = config[CONF_FOR]
|
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(
|
return await numeric_state_trigger.async_attach_trigger(
|
||||||
hass, numeric_state_config, action, automation_info, platform_type="device"
|
hass, numeric_state_config, action, automation_info, platform_type="device"
|
||||||
|
|
|
@ -162,7 +162,9 @@ async def async_attach_trigger(hass, config, action, automation_info):
|
||||||
if CONF_FOR in config:
|
if CONF_FOR in config:
|
||||||
numeric_state_config[CONF_FOR] = config[CONF_FOR]
|
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(
|
return await numeric_state_trigger.async_attach_trigger(
|
||||||
hass, numeric_state_config, action, automation_info, platform_type="device"
|
hass, numeric_state_config, action, automation_info, platform_type="device"
|
||||||
)
|
)
|
||||||
|
|
|
@ -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.const import ATTR_ENTITY_ID, ENTITY_MATCH_ALL, SERVICE_TURN_OFF
|
||||||
from homeassistant.core import Context
|
from homeassistant.core import Context
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
import homeassistant.util.dt as dt_util
|
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
|
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(
|
@pytest.mark.parametrize(
|
||||||
"below", (10, "input_number.value_10", "number.value_10", "sensor.value_10")
|
"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"
|
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."""
|
"""Test above cannot be above below."""
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
numeric_state_trigger.TRIGGER_SCHEMA(
|
await numeric_state_trigger.async_validate_trigger_config(
|
||||||
{"platform": "numeric_state", "above": 1200, "below": 1000}
|
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."""
|
"""Test input_number, number & sensor only is accepted for above/below."""
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
numeric_state_trigger.TRIGGER_SCHEMA(
|
await numeric_state_trigger.async_validate_trigger_config(
|
||||||
|
hass,
|
||||||
{
|
{
|
||||||
"platform": "numeric_state",
|
"platform": "numeric_state",
|
||||||
"above": "input_datetime.some_input",
|
"above": "input_datetime.some_input",
|
||||||
"below": 1000,
|
"below": 1000,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
numeric_state_trigger.TRIGGER_SCHEMA(
|
await numeric_state_trigger.async_validate_trigger_config(
|
||||||
|
hass,
|
||||||
{
|
{
|
||||||
"platform": "numeric_state",
|
"platform": "numeric_state",
|
||||||
"below": "input_datetime.some_input",
|
"below": "input_datetime.some_input",
|
||||||
"above": 1200,
|
"above": 1200,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue