State condition can also accept an input_* Entity ID as state value (#39691)
parent
165dd351b7
commit
1ec3446c56
|
@ -4,6 +4,7 @@ from collections import deque
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import functools as ft
|
import functools as ft
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Callable, Container, List, Optional, Set, Union, cast
|
from typing import Any, Callable, Container, List, Optional, Set, Union, cast
|
||||||
|
|
||||||
|
@ -48,6 +49,10 @@ ASYNC_FROM_CONFIG_FORMAT = "async_{}_from_config"
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
INPUT_ENTITY_ID = re.compile(
|
||||||
|
r"^input_(?:select|text|number|boolean|datetime)\.(?!.+__)(?!_)[\da-z_]+(?<!_)$"
|
||||||
|
)
|
||||||
|
|
||||||
ConditionCheckerType = Callable[[HomeAssistant, TemplateVarsType], bool]
|
ConditionCheckerType = Callable[[HomeAssistant, TemplateVarsType], bool]
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,13 +313,25 @@ def state(
|
||||||
|
|
||||||
assert isinstance(entity, State)
|
assert isinstance(entity, State)
|
||||||
|
|
||||||
|
if attribute is None:
|
||||||
|
value = entity.state
|
||||||
|
else:
|
||||||
|
value = str(entity.attributes.get(attribute))
|
||||||
|
|
||||||
if isinstance(req_state, str):
|
if isinstance(req_state, str):
|
||||||
req_state = [req_state]
|
req_state = [req_state]
|
||||||
|
|
||||||
if attribute is None:
|
is_state = False
|
||||||
is_state = entity.state in req_state
|
for req_state_value in req_state:
|
||||||
else:
|
state_value = req_state_value
|
||||||
is_state = str(entity.attributes.get(attribute)) in req_state
|
if INPUT_ENTITY_ID.match(req_state_value) is not None:
|
||||||
|
state_entity = hass.states.get(req_state_value)
|
||||||
|
if not state_entity:
|
||||||
|
continue
|
||||||
|
state_value = state_entity.state
|
||||||
|
is_state = value == state_value
|
||||||
|
if is_state:
|
||||||
|
break
|
||||||
|
|
||||||
if for_period is None or not is_state:
|
if for_period is None or not is_state:
|
||||||
return is_state
|
return is_state
|
||||||
|
|
|
@ -443,6 +443,88 @@ async def test_state_attribute(hass):
|
||||||
assert not test(hass)
|
assert not test(hass)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_state_using_input_entities(hass):
|
||||||
|
"""Test state conditions using input_* entities."""
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"input_text",
|
||||||
|
{
|
||||||
|
"input_text": {
|
||||||
|
"hello": {"initial": "goodbye"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"input_select",
|
||||||
|
{
|
||||||
|
"input_select": {
|
||||||
|
"hello": {"options": ["cya", "goodbye", "welcome"], "initial": "cya"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
test = await condition.async_from_config(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
"condition": "and",
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": "sensor.salut",
|
||||||
|
"state": [
|
||||||
|
"input_text.hello",
|
||||||
|
"input_select.hello",
|
||||||
|
"input_number.not_exist",
|
||||||
|
"salut",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "goodbye")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "salut")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "hello")
|
||||||
|
assert not test(hass)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"input_text",
|
||||||
|
"set_value",
|
||||||
|
{
|
||||||
|
"entity_id": "input_text.hello",
|
||||||
|
"value": "hi",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert not test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "hi")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "cya")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"input_select",
|
||||||
|
"select_option",
|
||||||
|
{
|
||||||
|
"entity_id": "input_select.hello",
|
||||||
|
"option": "welcome",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert not test(hass)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.salut", "welcome")
|
||||||
|
assert test(hass)
|
||||||
|
|
||||||
|
|
||||||
async def test_numeric_state_multiple_entities(hass):
|
async def test_numeric_state_multiple_entities(hass):
|
||||||
"""Test with multiple entities in condition."""
|
"""Test with multiple entities in condition."""
|
||||||
test = await condition.async_from_config(
|
test = await condition.async_from_config(
|
||||||
|
|
Loading…
Reference in New Issue