State condition can also accept an input_* Entity ID as state value (#39691)

pull/39703/head
Franck Nijhof 2020-09-07 00:36:01 +02:00 committed by GitHub
parent 165dd351b7
commit 1ec3446c56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 4 deletions

View File

@ -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

View File

@ -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(