Teach state and numeric_state conditions about entity registry ids (#60841)
This commit is contained in:
parent
a07f75c6b0
commit
0e3bc21d54
23 changed files with 236 additions and 31 deletions
|
@ -27,7 +27,7 @@ from homeassistant.const import (
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
STATE_ALARM_TRIGGERED,
|
STATE_ALARM_TRIGGERED,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||||
from homeassistant.helpers.entity import get_supported_features
|
from homeassistant.helpers.entity import get_supported_features
|
||||||
|
@ -104,7 +104,10 @@ async def async_get_conditions(
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
@callback
|
||||||
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == CONDITION_TRIGGERED:
|
if config[CONF_TYPE] == CONDITION_TRIGGERED:
|
||||||
state = STATE_ALARM_TRIGGERED
|
state = STATE_ALARM_TRIGGERED
|
||||||
|
|
|
@ -264,7 +264,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
condition_type = config[CONF_TYPE]
|
condition_type = config[CONF_TYPE]
|
||||||
if condition_type in IS_ON:
|
if condition_type in IS_ON:
|
||||||
|
@ -279,6 +281,7 @@ def async_condition_from_config(config: ConfigType) -> condition.ConditionChecke
|
||||||
if CONF_FOR in config:
|
if CONF_FOR in config:
|
||||||
state_config[CONF_FOR] = config[CONF_FOR]
|
state_config[CONF_FOR] = config[CONF_FOR]
|
||||||
state_config = cv.STATE_CONDITION_SCHEMA(state_config)
|
state_config = cv.STATE_CONDITION_SCHEMA(state_config)
|
||||||
|
state_config = condition.state_validate_config(hass, state_config)
|
||||||
|
|
||||||
return condition.state_from_config(state_config)
|
return condition.state_from_config(state_config)
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_hvac_mode":
|
if config[CONF_TYPE] == "is_hvac_mode":
|
||||||
attribute = const.ATTR_HVAC_MODE
|
attribute = const.ATTR_HVAC_MODE
|
||||||
|
|
|
@ -119,7 +119,9 @@ async def async_get_condition_capabilities(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] in STATE_CONDITION_TYPES:
|
if config[CONF_TYPE] in STATE_CONDITION_TYPES:
|
||||||
if config[CONF_TYPE] == "is_open":
|
if config[CONF_TYPE] == "is_open":
|
||||||
|
|
|
@ -127,7 +127,9 @@ async def async_call_action_from_config(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
if config[CONF_TYPE] == CONF_IS_ON:
|
if config[CONF_TYPE] == CONF_IS_ON:
|
||||||
stat = "on"
|
stat = "on"
|
||||||
|
@ -142,6 +144,7 @@ def async_condition_from_config(config: ConfigType) -> condition.ConditionChecke
|
||||||
state_config[CONF_FOR] = config[CONF_FOR]
|
state_config[CONF_FOR] = config[CONF_FOR]
|
||||||
|
|
||||||
state_config = cv.STATE_CONDITION_SCHEMA(state_config)
|
state_config = cv.STATE_CONDITION_SCHEMA(state_config)
|
||||||
|
state_config = condition.state_validate_config(hass, state_config)
|
||||||
return condition.state_from_config(state_config)
|
return condition.state_from_config(state_config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
reverse = config[CONF_TYPE] == "is_not_home"
|
reverse = config[CONF_TYPE] == "is_not_home"
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_on":
|
if config[CONF_TYPE] == "is_on":
|
||||||
state = STATE_ON
|
state = STATE_ON
|
||||||
|
|
|
@ -65,12 +65,14 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_mode":
|
if config[CONF_TYPE] == "is_mode":
|
||||||
attribute = ATTR_MODE
|
attribute = ATTR_MODE
|
||||||
else:
|
else:
|
||||||
return toggle_entity.async_condition_from_config(config)
|
return toggle_entity.async_condition_from_config(hass, config)
|
||||||
|
|
||||||
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
|
def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
|
||||||
"""Test if an entity is a certain state."""
|
"""Test if an entity is a certain state."""
|
||||||
|
|
|
@ -19,9 +19,11 @@ CONDITION_SCHEMA = toggle_entity.CONDITION_SCHEMA.extend(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
return toggle_entity.async_condition_from_config(config)
|
return toggle_entity.async_condition_from_config(hass, config)
|
||||||
|
|
||||||
|
|
||||||
async def async_get_conditions(
|
async def async_get_conditions(
|
||||||
|
|
|
@ -67,7 +67,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_jammed":
|
if config[CONF_TYPE] == "is_jammed":
|
||||||
state = STATE_JAMMED
|
state = STATE_JAMMED
|
||||||
|
|
|
@ -59,7 +59,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_playing":
|
if config[CONF_TYPE] == "is_playing":
|
||||||
state = STATE_PLAYING
|
state = STATE_PLAYING
|
||||||
|
|
|
@ -19,9 +19,11 @@ CONDITION_SCHEMA = toggle_entity.CONDITION_SCHEMA.extend(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
return toggle_entity.async_condition_from_config(config)
|
return toggle_entity.async_condition_from_config(hass, config)
|
||||||
|
|
||||||
|
|
||||||
async def async_get_conditions(
|
async def async_get_conditions(
|
||||||
|
|
|
@ -52,7 +52,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
|
|
@ -186,7 +186,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
numeric_state_config = {
|
numeric_state_config = {
|
||||||
condition.CONF_CONDITION: "numeric_state",
|
condition.CONF_CONDITION: "numeric_state",
|
||||||
|
@ -198,6 +200,9 @@ def async_condition_from_config(config: ConfigType) -> condition.ConditionChecke
|
||||||
numeric_state_config[condition.CONF_BELOW] = config[CONF_BELOW]
|
numeric_state_config[condition.CONF_BELOW] = config[CONF_BELOW]
|
||||||
|
|
||||||
numeric_state_config = cv.NUMERIC_STATE_CONDITION_SCHEMA(numeric_state_config)
|
numeric_state_config = cv.NUMERIC_STATE_CONDITION_SCHEMA(numeric_state_config)
|
||||||
|
numeric_state_config = condition.numeric_state_validate_config(
|
||||||
|
hass, numeric_state_config
|
||||||
|
)
|
||||||
return condition.async_numeric_state_from_config(numeric_state_config)
|
return condition.async_numeric_state_from_config(numeric_state_config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,11 @@ CONDITION_SCHEMA = toggle_entity.CONDITION_SCHEMA.extend(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> ConditionCheckerType:
|
||||||
"""Evaluate state based on configuration."""
|
"""Evaluate state based on configuration."""
|
||||||
return toggle_entity.async_condition_from_config(config)
|
return toggle_entity.async_condition_from_config(hass, config)
|
||||||
|
|
||||||
|
|
||||||
async def async_get_conditions(
|
async def async_get_conditions(
|
||||||
|
|
|
@ -53,7 +53,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_docked":
|
if config[CONF_TYPE] == "is_docked":
|
||||||
test_states = [STATE_DOCKED]
|
test_states = [STATE_DOCKED]
|
||||||
|
|
|
@ -147,7 +147,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
condition_type = config[CONF_TYPE]
|
condition_type = config[CONF_TYPE]
|
||||||
device_id = config[CONF_DEVICE_ID]
|
device_id = config[CONF_DEVICE_ID]
|
||||||
|
|
|
@ -51,7 +51,7 @@ from homeassistant.exceptions import (
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
TemplateError,
|
TemplateError,
|
||||||
)
|
)
|
||||||
import homeassistant.helpers.config_validation as cv
|
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||||
from homeassistant.helpers.sun import get_astral_event_date
|
from homeassistant.helpers.sun import get_astral_event_date
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||||
|
@ -71,8 +71,9 @@ from .trace import (
|
||||||
|
|
||||||
# mypy: disallow-any-generics
|
# mypy: disallow-any-generics
|
||||||
|
|
||||||
FROM_CONFIG_FORMAT = "{}_from_config"
|
|
||||||
ASYNC_FROM_CONFIG_FORMAT = "async_{}_from_config"
|
ASYNC_FROM_CONFIG_FORMAT = "async_{}_from_config"
|
||||||
|
FROM_CONFIG_FORMAT = "{}_from_config"
|
||||||
|
VALIDATE_CONFIG_FORMAT = "{}_validate_config"
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -885,7 +886,7 @@ async def async_device_from_config(
|
||||||
return trace_condition_function(
|
return trace_condition_function(
|
||||||
cast(
|
cast(
|
||||||
ConditionCheckerType,
|
ConditionCheckerType,
|
||||||
platform.async_condition_from_config(config), # type: ignore
|
platform.async_condition_from_config(hass, config), # type: ignore
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -908,6 +909,30 @@ async def async_trigger_from_config(
|
||||||
return trigger_if
|
return trigger_if
|
||||||
|
|
||||||
|
|
||||||
|
def numeric_state_validate_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> ConfigType:
|
||||||
|
"""Validate numeric_state condition config."""
|
||||||
|
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
config = dict(config)
|
||||||
|
config[CONF_ENTITY_ID] = er.async_resolve_entity_ids(
|
||||||
|
registry, cv.entity_ids_or_uuids(config[CONF_ENTITY_ID])
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def state_validate_config(hass: HomeAssistant, config: ConfigType) -> ConfigType:
|
||||||
|
"""Validate state condition config."""
|
||||||
|
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
config = dict(config)
|
||||||
|
config[CONF_ENTITY_ID] = er.async_resolve_entity_ids(
|
||||||
|
registry, cv.entity_ids_or_uuids(config[CONF_ENTITY_ID])
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
async def async_validate_condition_config(
|
async def async_validate_condition_config(
|
||||||
hass: HomeAssistant, config: ConfigType | Template
|
hass: HomeAssistant, config: ConfigType | Template
|
||||||
) -> ConfigType | Template:
|
) -> ConfigType | Template:
|
||||||
|
@ -933,6 +958,12 @@ async def async_validate_condition_config(
|
||||||
return await platform.async_validate_condition_config(hass, config) # type: ignore
|
return await platform.async_validate_condition_config(hass, config) # type: ignore
|
||||||
return cast(ConfigType, platform.CONDITION_SCHEMA(config)) # type: ignore
|
return cast(ConfigType, platform.CONDITION_SCHEMA(config)) # type: ignore
|
||||||
|
|
||||||
|
if condition in ("numeric_state", "state"):
|
||||||
|
validator = getattr(
|
||||||
|
sys.modules[__name__], VALIDATE_CONFIG_FORMAT.format(condition)
|
||||||
|
)
|
||||||
|
return validator(hass, config) # type: ignore
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1028,7 +1028,7 @@ NUMERIC_STATE_CONDITION_SCHEMA = vol.All(
|
||||||
{
|
{
|
||||||
**CONDITION_BASE_SCHEMA,
|
**CONDITION_BASE_SCHEMA,
|
||||||
vol.Required(CONF_CONDITION): "numeric_state",
|
vol.Required(CONF_CONDITION): "numeric_state",
|
||||||
vol.Required(CONF_ENTITY_ID): entity_ids,
|
vol.Required(CONF_ENTITY_ID): entity_ids_or_uuids,
|
||||||
vol.Optional(CONF_ATTRIBUTE): str,
|
vol.Optional(CONF_ATTRIBUTE): str,
|
||||||
CONF_BELOW: NUMERIC_STATE_THRESHOLD_SCHEMA,
|
CONF_BELOW: NUMERIC_STATE_THRESHOLD_SCHEMA,
|
||||||
CONF_ABOVE: NUMERIC_STATE_THRESHOLD_SCHEMA,
|
CONF_ABOVE: NUMERIC_STATE_THRESHOLD_SCHEMA,
|
||||||
|
@ -1041,7 +1041,7 @@ NUMERIC_STATE_CONDITION_SCHEMA = vol.All(
|
||||||
STATE_CONDITION_BASE_SCHEMA = {
|
STATE_CONDITION_BASE_SCHEMA = {
|
||||||
**CONDITION_BASE_SCHEMA,
|
**CONDITION_BASE_SCHEMA,
|
||||||
vol.Required(CONF_CONDITION): "state",
|
vol.Required(CONF_CONDITION): "state",
|
||||||
vol.Required(CONF_ENTITY_ID): entity_ids,
|
vol.Required(CONF_ENTITY_ID): entity_ids_or_uuids,
|
||||||
vol.Optional(CONF_ATTRIBUTE): str,
|
vol.Optional(CONF_ATTRIBUTE): str,
|
||||||
vol.Optional(CONF_FOR): positive_time_period,
|
vol.Optional(CONF_FOR): positive_time_period,
|
||||||
# To support use_trigger_value in automation
|
# To support use_trigger_value in automation
|
||||||
|
|
|
@ -58,7 +58,9 @@ async def async_get_conditions(
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_condition_from_config(config: ConfigType) -> condition.ConditionCheckerType:
|
def async_condition_from_config(
|
||||||
|
hass: HomeAssistant, config: ConfigType
|
||||||
|
) -> condition.ConditionCheckerType:
|
||||||
"""Create a function to test a device condition."""
|
"""Create a function to test a device condition."""
|
||||||
if config[CONF_TYPE] == "is_on":
|
if config[CONF_TYPE] == "is_on":
|
||||||
state = STATE_ON
|
state = STATE_ON
|
||||||
|
|
|
@ -552,7 +552,7 @@ async def test_failure_scenarios(hass, client, hank_binary_switch, integration):
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(HomeAssistantError):
|
||||||
await device_condition.async_condition_from_config(
|
await device_condition.async_condition_from_config(
|
||||||
{"type": "failed.test", "device_id": device.id}
|
hass, {"type": "failed.test", "device_id": device.id}
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
|
|
|
@ -16,7 +16,12 @@ from homeassistant.const import (
|
||||||
SUN_EVENT_SUNSET,
|
SUN_EVENT_SUNSET,
|
||||||
)
|
)
|
||||||
from homeassistant.exceptions import ConditionError, HomeAssistantError
|
from homeassistant.exceptions import ConditionError, HomeAssistantError
|
||||||
from homeassistant.helpers import condition, config_validation as cv, trace
|
from homeassistant.helpers import (
|
||||||
|
condition,
|
||||||
|
config_validation as cv,
|
||||||
|
entity_registry as er,
|
||||||
|
trace,
|
||||||
|
)
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
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
|
||||||
|
@ -1107,6 +1112,29 @@ async def test_state_attribute_boolean(hass):
|
||||||
assert test(hass)
|
assert test(hass)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_state_entity_registry_id(hass):
|
||||||
|
"""Test with entity specified by entity registry id."""
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
entry = registry.async_get_or_create(
|
||||||
|
"switch", "hue", "1234", suggested_object_id="test"
|
||||||
|
)
|
||||||
|
assert entry.entity_id == "switch.test"
|
||||||
|
config = {
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": entry.id,
|
||||||
|
"state": "on",
|
||||||
|
}
|
||||||
|
config = cv.CONDITION_SCHEMA(config)
|
||||||
|
config = await condition.async_validate_condition_config(hass, config)
|
||||||
|
test = await condition.async_from_config(hass, config)
|
||||||
|
|
||||||
|
hass.states.async_set("switch.test", "on")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("switch.test", "off")
|
||||||
|
assert not test(hass)
|
||||||
|
|
||||||
|
|
||||||
async def test_state_using_input_entities(hass):
|
async def test_state_using_input_entities(hass):
|
||||||
"""Test state conditions using input_* entities."""
|
"""Test state conditions using input_* entities."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
|
@ -1419,6 +1447,29 @@ async def test_numeric_state_attribute(hass):
|
||||||
assert not test(hass)
|
assert not test(hass)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_numeric_state_entity_registry_id(hass):
|
||||||
|
"""Test with entity specified by entity registry id."""
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
entry = registry.async_get_or_create(
|
||||||
|
"sensor", "hue", "1234", suggested_object_id="test"
|
||||||
|
)
|
||||||
|
assert entry.entity_id == "sensor.test"
|
||||||
|
config = {
|
||||||
|
"condition": "numeric_state",
|
||||||
|
"entity_id": entry.id,
|
||||||
|
"above": 100,
|
||||||
|
}
|
||||||
|
config = cv.CONDITION_SCHEMA(config)
|
||||||
|
config = await condition.async_validate_condition_config(hass, config)
|
||||||
|
test = await condition.async_from_config(hass, config)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test", "110")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test", "90")
|
||||||
|
assert not test(hass)
|
||||||
|
|
||||||
|
|
||||||
async def test_numeric_state_using_input_number(hass):
|
async def test_numeric_state_using_input_number(hass):
|
||||||
"""Test numeric_state conditions using input_number entities."""
|
"""Test numeric_state conditions using input_number entities."""
|
||||||
hass.states.async_set("number.low", 10)
|
hass.states.async_set("number.low", 10)
|
||||||
|
|
|
@ -25,7 +25,13 @@ from homeassistant.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import SERVICE_CALL_LIMIT, Context, CoreState, callback
|
from homeassistant.core import SERVICE_CALL_LIMIT, Context, CoreState, callback
|
||||||
from homeassistant.exceptions import ConditionError, ServiceNotFound
|
from homeassistant.exceptions import ConditionError, ServiceNotFound
|
||||||
from homeassistant.helpers import config_validation as cv, script, template, trace
|
from homeassistant.helpers import (
|
||||||
|
config_validation as cv,
|
||||||
|
entity_registry as er,
|
||||||
|
script,
|
||||||
|
template,
|
||||||
|
trace,
|
||||||
|
)
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
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
|
||||||
|
@ -1492,6 +1498,81 @@ async def test_condition_basic(hass, caplog):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_condition_validation(hass, caplog):
|
||||||
|
"""Test if we can use conditions which validate late in a script."""
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
entry = registry.async_get_or_create(
|
||||||
|
"test", "hue", "1234", suggested_object_id="entity"
|
||||||
|
)
|
||||||
|
assert entry.entity_id == "test.entity"
|
||||||
|
event = "test_event"
|
||||||
|
events = async_capture_events(hass, event)
|
||||||
|
alias = "condition step"
|
||||||
|
sequence = cv.SCRIPT_SCHEMA(
|
||||||
|
[
|
||||||
|
{"event": event},
|
||||||
|
{
|
||||||
|
"alias": alias,
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": entry.id,
|
||||||
|
"state": "hello",
|
||||||
|
},
|
||||||
|
{"event": event},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
sequence = await script.async_validate_actions_config(hass, sequence)
|
||||||
|
script_obj = script.Script(hass, sequence, "Test Name", "test_domain")
|
||||||
|
|
||||||
|
hass.states.async_set("test.entity", "hello")
|
||||||
|
await script_obj.async_run(context=Context())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert f"Test condition {alias}: True" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
assert len(events) == 2
|
||||||
|
|
||||||
|
assert_action_trace(
|
||||||
|
{
|
||||||
|
"0": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||||
|
"1": [{"result": {"result": True}}],
|
||||||
|
"1/entity_id/0": [
|
||||||
|
{"result": {"result": True, "state": "hello", "wanted_state": "hello"}}
|
||||||
|
],
|
||||||
|
"2": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("test.entity", "goodbye")
|
||||||
|
|
||||||
|
await script_obj.async_run(context=Context())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert f"Test condition {alias}: False" in caplog.text
|
||||||
|
assert len(events) == 3
|
||||||
|
|
||||||
|
assert_action_trace(
|
||||||
|
{
|
||||||
|
"0": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||||
|
"1": [
|
||||||
|
{
|
||||||
|
"error_type": script._StopScript,
|
||||||
|
"result": {"result": False},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1/entity_id/0": [
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"result": False,
|
||||||
|
"state": "goodbye",
|
||||||
|
"wanted_state": "hello",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
expected_script_execution="aborted",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.helpers.script.condition.async_from_config")
|
@patch("homeassistant.helpers.script.condition.async_from_config")
|
||||||
async def test_condition_created_once(async_from_config, hass):
|
async def test_condition_created_once(async_from_config, hass):
|
||||||
"""Test that the conditions do not get created multiple times."""
|
"""Test that the conditions do not get created multiple times."""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue