[core] Pass a single condition to actions directly instead of wrapping it in a group (#19223)

This commit is contained in:
J. Nick Koston
2026-10-09 09:24:32 -10:00
committed by GitHub
parent 7ab24bf850
commit c859c347cb
4 changed files with 75 additions and 51 deletions
+6 -51
View File
@@ -699,52 +699,20 @@ XorCondition = cg.esphome_ns.class_("XorCondition", Condition)
@register_condition("and", AndCondition, validate_condition_list)
async def and_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("or", OrCondition, validate_condition_list)
async def or_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("all", AndCondition, validate_condition_list)
async def all_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("or", OrCondition, validate_condition_list)
@register_condition("any", OrCondition, validate_condition_list)
async def any_condition_to_code(
@register_condition("xor", XorCondition, validate_condition_list)
async def condition_group_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
# A group of one is that condition for and, or and xor; skip the wrapper.
if len(conditions) == 1:
return conditions[0]
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@@ -761,19 +729,6 @@ async def not_condition_to_code(
return cg.new_Pvariable(condition_id, template_arg, condition)
@register_condition("xor", XorCondition, validate_condition_list)
async def xor_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(
condition_id, cg.TemplateArguments(len(conditions), *template_arg), conditions
)
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
async def lambda_condition_to_code(
config: ConfigType,
@@ -0,0 +1,44 @@
---
esphome:
name: test
esp32:
board: nodemcu-32s
logger:
binary_sensor:
- platform: template
id: single_and
on_press:
- if:
condition:
- lambda: return true;
then:
- logger.log: single and
- platform: template
id: single_or
on_press:
- if:
any:
- lambda: return true;
then:
- logger.log: single or
- platform: template
id: double_and
on_press:
- if:
condition:
- lambda: return true;
- lambda: return false;
then:
- logger.log: double and
- platform: template
id: single_xor
on_press:
- if:
condition:
xor:
- lambda: return true;
then:
- logger.log: single xor
@@ -0,0 +1,25 @@
"""Tests for and/or condition group codegen."""
from collections.abc import Callable
from pathlib import Path
import re
def test_single_condition_groups_are_unwrapped(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
"""A group of one condition is passed to the action directly."""
main_cpp = generate_main(component_config_path("condition_groups.yaml"))
assert "IfAction<false>(lambdacondition_id);" in main_cpp
assert "IfAction<false>(lambdacondition_id_2);" in main_cpp
group = re.search(
r"new\((\w+)\) AndCondition<2>\(\{lambdacondition_id_3, lambdacondition_id_4\}\);",
main_cpp,
)
assert group is not None
assert f"IfAction<false>({group.group(1)});" in main_cpp
# xor of one condition equals that condition, so it is unwrapped too.
assert "IfAction<false>(lambdacondition_id_5);" in main_cpp
assert "XorCondition<" not in main_cpp