mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Fix logic of disabled condition for "OR" (#79718)
This commit is contained in:
parent
c6f60bf45d
commit
156307f3f2
@ -870,7 +870,7 @@ async def _async_process_if(
|
|||||||
for index, check in enumerate(checks):
|
for index, check in enumerate(checks):
|
||||||
try:
|
try:
|
||||||
with trace_path(["condition", str(index)]):
|
with trace_path(["condition", str(index)]):
|
||||||
if not check(hass, variables):
|
if check(hass, variables) is False:
|
||||||
return False
|
return False
|
||||||
except ConditionError as ex:
|
except ConditionError as ex:
|
||||||
errors.append(
|
errors.append(
|
||||||
|
@ -10,7 +10,7 @@ import functools as ft
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, cast
|
from typing import Any, Optional, cast
|
||||||
|
|
||||||
from homeassistant.components import zone as zone_cmp
|
from homeassistant.components import zone as zone_cmp
|
||||||
from homeassistant.components.device_automation import condition as device_condition
|
from homeassistant.components.device_automation import condition as device_condition
|
||||||
@ -80,7 +80,7 @@ INPUT_ENTITY_ID = re.compile(
|
|||||||
r"^input_(?:select|text|number|boolean|datetime)\.(?!.+__)(?!_)[\da-z_]+(?<!_)$"
|
r"^input_(?:select|text|number|boolean|datetime)\.(?!.+__)(?!_)[\da-z_]+(?<!_)$"
|
||||||
)
|
)
|
||||||
|
|
||||||
ConditionCheckerType = Callable[[HomeAssistant, TemplateVarsType], bool]
|
ConditionCheckerType = Callable[[HomeAssistant, TemplateVarsType], Optional[bool]]
|
||||||
|
|
||||||
|
|
||||||
def condition_trace_append(variables: TemplateVarsType, path: str) -> TraceElement:
|
def condition_trace_append(variables: TemplateVarsType, path: str) -> TraceElement:
|
||||||
@ -139,7 +139,7 @@ def trace_condition_function(condition: ConditionCheckerType) -> ConditionChecke
|
|||||||
"""Wrap a condition function to enable basic tracing."""
|
"""Wrap a condition function to enable basic tracing."""
|
||||||
|
|
||||||
@ft.wraps(condition)
|
@ft.wraps(condition)
|
||||||
def wrapper(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool:
|
def wrapper(hass: HomeAssistant, variables: TemplateVarsType = None) -> bool | None:
|
||||||
"""Trace condition."""
|
"""Trace condition."""
|
||||||
with trace_condition(variables):
|
with trace_condition(variables):
|
||||||
result = condition(hass, variables)
|
result = condition(hass, variables)
|
||||||
@ -173,9 +173,9 @@ async def async_from_config(
|
|||||||
@trace_condition_function
|
@trace_condition_function
|
||||||
def disabled_condition(
|
def disabled_condition(
|
||||||
hass: HomeAssistant, variables: TemplateVarsType = None
|
hass: HomeAssistant, variables: TemplateVarsType = None
|
||||||
) -> bool:
|
) -> bool | None:
|
||||||
"""Condition not enabled, will always pass."""
|
"""Condition not enabled, will act as if it didn't exist."""
|
||||||
return True
|
return None
|
||||||
|
|
||||||
return disabled_condition
|
return disabled_condition
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ async def async_and_from_config(
|
|||||||
for index, check in enumerate(checks):
|
for index, check in enumerate(checks):
|
||||||
try:
|
try:
|
||||||
with trace_path(["conditions", str(index)]):
|
with trace_path(["conditions", str(index)]):
|
||||||
if not check(hass, variables):
|
if check(hass, variables) is False:
|
||||||
return False
|
return False
|
||||||
except ConditionError as ex:
|
except ConditionError as ex:
|
||||||
errors.append(
|
errors.append(
|
||||||
@ -235,7 +235,7 @@ async def async_or_from_config(
|
|||||||
for index, check in enumerate(checks):
|
for index, check in enumerate(checks):
|
||||||
try:
|
try:
|
||||||
with trace_path(["conditions", str(index)]):
|
with trace_path(["conditions", str(index)]):
|
||||||
if check(hass, variables):
|
if check(hass, variables) is True:
|
||||||
return True
|
return True
|
||||||
except ConditionError as ex:
|
except ConditionError as ex:
|
||||||
errors.append(
|
errors.append(
|
||||||
|
@ -3291,7 +3291,7 @@ async def test_platform_async_validate_condition_config(hass):
|
|||||||
|
|
||||||
|
|
||||||
async def test_disabled_condition(hass: HomeAssistant) -> None:
|
async def test_disabled_condition(hass: HomeAssistant) -> None:
|
||||||
"""Test a disabled condition always passes."""
|
"""Test a disabled condition returns none."""
|
||||||
config = {
|
config = {
|
||||||
"enabled": False,
|
"enabled": False,
|
||||||
"condition": "state",
|
"condition": "state",
|
||||||
@ -3303,8 +3303,138 @@ async def test_disabled_condition(hass: HomeAssistant) -> None:
|
|||||||
test = await condition.async_from_config(hass, config)
|
test = await condition.async_from_config(hass, config)
|
||||||
|
|
||||||
hass.states.async_set("binary_sensor.test", "on")
|
hass.states.async_set("binary_sensor.test", "on")
|
||||||
assert test(hass)
|
assert test(hass) is None
|
||||||
|
|
||||||
# Still passses, condition is not enabled
|
# Still passses, condition is not enabled
|
||||||
hass.states.async_set("binary_sensor.test", "off")
|
hass.states.async_set("binary_sensor.test", "off")
|
||||||
|
assert test(hass) is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_and_condition_with_disabled_condition(hass):
|
||||||
|
"""Test the 'and' condition with one of the conditions disabled."""
|
||||||
|
config = {
|
||||||
|
"alias": "And Condition",
|
||||||
|
"condition": "and",
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"enabled": False,
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"state": "100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "numeric_state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"below": 110,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
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.temperature", 120)
|
||||||
|
assert not test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": False}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": False}}],
|
||||||
|
"conditions/1/entity_id/0": [
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"result": False,
|
||||||
|
"wanted_state_below": 110.0,
|
||||||
|
"state": 120.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 105)
|
||||||
assert test(hass)
|
assert test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": True}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": True}}],
|
||||||
|
"conditions/1/entity_id/0": [{"result": {"result": True, "state": 105.0}}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 100)
|
||||||
|
assert test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": True}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": True}}],
|
||||||
|
"conditions/1/entity_id/0": [{"result": {"result": True, "state": 100.0}}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_or_condition_with_disabled_condition(hass):
|
||||||
|
"""Test the 'or' condition with one of the conditions disabled."""
|
||||||
|
config = {
|
||||||
|
"alias": "Or Condition",
|
||||||
|
"condition": "or",
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"enabled": False,
|
||||||
|
"condition": "state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"state": "100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "numeric_state",
|
||||||
|
"entity_id": "sensor.temperature",
|
||||||
|
"below": 110,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
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.temperature", 120)
|
||||||
|
assert not test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": False}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": False}}],
|
||||||
|
"conditions/1/entity_id/0": [
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"result": False,
|
||||||
|
"state": 120.0,
|
||||||
|
"wanted_state_below": 110.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 105)
|
||||||
|
assert test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": True}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": True}}],
|
||||||
|
"conditions/1/entity_id/0": [{"result": {"result": True, "state": 105.0}}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 100)
|
||||||
|
assert test(hass)
|
||||||
|
assert_condition_trace(
|
||||||
|
{
|
||||||
|
"": [{"result": {"result": True}}],
|
||||||
|
"conditions/0": [{"result": {"result": None}}],
|
||||||
|
"conditions/1": [{"result": {"result": True}}],
|
||||||
|
"conditions/1/entity_id/0": [{"result": {"result": True, "state": 100.0}}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user