Add support for multiple entity_ids in conditions (#36817)
parent
0a219081ea
commit
ba73ac12ba
|
@ -238,7 +238,7 @@ def async_numeric_state_from_config(
|
|||
"""Wrap action method with state based condition."""
|
||||
if config_validation:
|
||||
config = cv.NUMERIC_STATE_CONDITION_SCHEMA(config)
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
entity_ids = config.get(CONF_ENTITY_ID, [])
|
||||
below = config.get(CONF_BELOW)
|
||||
above = config.get(CONF_ABOVE)
|
||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||
|
@ -250,8 +250,11 @@ def async_numeric_state_from_config(
|
|||
if value_template is not None:
|
||||
value_template.hass = hass
|
||||
|
||||
return async_numeric_state(
|
||||
hass, entity_id, below, above, value_template, variables
|
||||
return all(
|
||||
async_numeric_state(
|
||||
hass, entity_id, below, above, value_template, variables
|
||||
)
|
||||
for entity_id in entity_ids
|
||||
)
|
||||
|
||||
return if_numeric_state
|
||||
|
@ -288,13 +291,15 @@ def state_from_config(
|
|||
"""Wrap action method with state based condition."""
|
||||
if config_validation:
|
||||
config = cv.STATE_CONDITION_SCHEMA(config)
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
entity_ids = config.get(CONF_ENTITY_ID, [])
|
||||
req_state = cast(str, config.get(CONF_STATE))
|
||||
for_period = config.get("for")
|
||||
|
||||
def if_state(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool:
|
||||
"""Test if condition."""
|
||||
return state(hass, entity_id, req_state, for_period)
|
||||
return all(
|
||||
state(hass, entity_id, req_state, for_period) for entity_id in entity_ids
|
||||
)
|
||||
|
||||
return if_state
|
||||
|
||||
|
@ -506,12 +511,12 @@ def zone_from_config(
|
|||
"""Wrap action method with zone based condition."""
|
||||
if config_validation:
|
||||
config = cv.ZONE_CONDITION_SCHEMA(config)
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
entity_ids = config.get(CONF_ENTITY_ID, [])
|
||||
zone_entity_id = config.get(CONF_ZONE)
|
||||
|
||||
def if_in_zone(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool:
|
||||
"""Test if condition."""
|
||||
return zone(hass, zone_entity_id, entity_id)
|
||||
return all(zone(hass, zone_entity_id, entity_id) for entity_id in entity_ids)
|
||||
|
||||
return if_in_zone
|
||||
|
||||
|
@ -556,7 +561,7 @@ async def async_validate_condition_config(
|
|||
@callback
|
||||
def async_extract_entities(config: ConfigType) -> Set[str]:
|
||||
"""Extract entities from a condition."""
|
||||
referenced = set()
|
||||
referenced: Set[str] = set()
|
||||
to_process = deque([config])
|
||||
|
||||
while to_process:
|
||||
|
@ -567,10 +572,13 @@ def async_extract_entities(config: ConfigType) -> Set[str]:
|
|||
to_process.extend(config["conditions"])
|
||||
continue
|
||||
|
||||
entity_id = config.get(CONF_ENTITY_ID)
|
||||
entity_ids = config.get(CONF_ENTITY_ID)
|
||||
|
||||
if entity_id is not None:
|
||||
referenced.add(entity_id)
|
||||
if isinstance(entity_ids, str):
|
||||
entity_ids = [entity_ids]
|
||||
|
||||
if entity_ids is not None:
|
||||
referenced.update(entity_ids)
|
||||
|
||||
return referenced
|
||||
|
||||
|
|
|
@ -844,7 +844,7 @@ NUMERIC_STATE_CONDITION_SCHEMA = vol.All(
|
|||
vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_CONDITION): "numeric_state",
|
||||
vol.Required(CONF_ENTITY_ID): entity_id,
|
||||
vol.Required(CONF_ENTITY_ID): entity_ids,
|
||||
CONF_BELOW: vol.Coerce(float),
|
||||
CONF_ABOVE: vol.Coerce(float),
|
||||
vol.Optional(CONF_VALUE_TEMPLATE): template,
|
||||
|
@ -857,7 +857,7 @@ STATE_CONDITION_SCHEMA = vol.All(
|
|||
vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_CONDITION): "state",
|
||||
vol.Required(CONF_ENTITY_ID): entity_id,
|
||||
vol.Required(CONF_ENTITY_ID): entity_ids,
|
||||
vol.Required(CONF_STATE): str,
|
||||
vol.Optional(CONF_FOR): vol.All(time_period, positive_timedelta),
|
||||
# To support use_trigger_value in automation
|
||||
|
@ -905,7 +905,7 @@ TIME_CONDITION_SCHEMA = vol.All(
|
|||
ZONE_CONDITION_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_CONDITION): "zone",
|
||||
vol.Required(CONF_ENTITY_ID): entity_id,
|
||||
vol.Required(CONF_ENTITY_ID): entity_ids,
|
||||
"zone": entity_id,
|
||||
# To support use_trigger_value in automation
|
||||
# Deprecated 2016/04/25
|
||||
|
|
|
@ -266,6 +266,123 @@ async def test_if_numeric_state_not_raise_on_unavailable(hass):
|
|||
assert len(logwarn.mock_calls) == 0
|
||||
|
||||
|
||||
async def test_state_multiple_entities(hass):
|
||||
"""Test with multiple entities in condition."""
|
||||
test = await condition.async_from_config(
|
||||
hass,
|
||||
{
|
||||
"condition": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "state",
|
||||
"entity_id": ["sensor.temperature_1", "sensor.temperature_2"],
|
||||
"state": "100",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 100)
|
||||
hass.states.async_set("sensor.temperature_2", 100)
|
||||
assert test(hass)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 101)
|
||||
hass.states.async_set("sensor.temperature_2", 100)
|
||||
assert not test(hass)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 100)
|
||||
hass.states.async_set("sensor.temperature_2", 101)
|
||||
assert not test(hass)
|
||||
|
||||
|
||||
async def test_numeric_state_multiple_entities(hass):
|
||||
"""Test with multiple entities in condition."""
|
||||
test = await condition.async_from_config(
|
||||
hass,
|
||||
{
|
||||
"condition": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "numeric_state",
|
||||
"entity_id": ["sensor.temperature_1", "sensor.temperature_2"],
|
||||
"below": 50,
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 49)
|
||||
hass.states.async_set("sensor.temperature_2", 49)
|
||||
assert test(hass)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 50)
|
||||
hass.states.async_set("sensor.temperature_2", 49)
|
||||
assert not test(hass)
|
||||
|
||||
hass.states.async_set("sensor.temperature_1", 49)
|
||||
hass.states.async_set("sensor.temperature_2", 50)
|
||||
assert not test(hass)
|
||||
|
||||
|
||||
async def test_zone_multiple_entities(hass):
|
||||
"""Test with multiple entities in condition."""
|
||||
test = await condition.async_from_config(
|
||||
hass,
|
||||
{
|
||||
"condition": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "zone",
|
||||
"entity_id": ["device_tracker.person_1", "device_tracker.person_2"],
|
||||
"zone": "zone.home",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
"zone.home",
|
||||
"zoning",
|
||||
{"name": "home", "latitude": 2.1, "longitude": 1.1, "radius": 10},
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_1",
|
||||
"home",
|
||||
{"friendly_name": "person_1", "latitude": 2.1, "longitude": 1.1},
|
||||
)
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_2",
|
||||
"home",
|
||||
{"friendly_name": "person_2", "latitude": 2.1, "longitude": 1.1},
|
||||
)
|
||||
assert test(hass)
|
||||
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_1",
|
||||
"home",
|
||||
{"friendly_name": "person_1", "latitude": 20.1, "longitude": 10.1},
|
||||
)
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_2",
|
||||
"home",
|
||||
{"friendly_name": "person_2", "latitude": 2.1, "longitude": 1.1},
|
||||
)
|
||||
assert not test(hass)
|
||||
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_1",
|
||||
"home",
|
||||
{"friendly_name": "person_1", "latitude": 2.1, "longitude": 1.1},
|
||||
)
|
||||
hass.states.async_set(
|
||||
"device_tracker.person_2",
|
||||
"home",
|
||||
{"friendly_name": "person_2", "latitude": 20.1, "longitude": 10.1},
|
||||
)
|
||||
assert not test(hass)
|
||||
|
||||
|
||||
async def test_extract_entities():
|
||||
"""Test extracting entities."""
|
||||
assert condition.async_extract_entities(
|
||||
|
@ -312,6 +429,16 @@ async def test_extract_entities():
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"condition": "state",
|
||||
"entity_id": ["sensor.temperature_7", "sensor.temperature_8"],
|
||||
"state": "100",
|
||||
},
|
||||
{
|
||||
"condition": "numeric_state",
|
||||
"entity_id": ["sensor.temperature_9", "sensor.temperature_10"],
|
||||
"below": 110,
|
||||
},
|
||||
],
|
||||
}
|
||||
) == {
|
||||
|
@ -321,6 +448,10 @@ async def test_extract_entities():
|
|||
"sensor.temperature_4",
|
||||
"sensor.temperature_5",
|
||||
"sensor.temperature_6",
|
||||
"sensor.temperature_7",
|
||||
"sensor.temperature_8",
|
||||
"sensor.temperature_9",
|
||||
"sensor.temperature_10",
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue