mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 17:18:40 +00:00
deferred
This commit is contained in:
+16
-15
@@ -62,18 +62,18 @@ def register_action(
|
||||
action_type: MockObjClass,
|
||||
schema: cv.Schema,
|
||||
*,
|
||||
deferred: bool = True,
|
||||
synchronous: bool = False,
|
||||
):
|
||||
"""Register an action type.
|
||||
|
||||
Actions default to ``deferred=True`` (safe default), meaning string
|
||||
Actions default to ``synchronous=False`` (safe default), meaning string
|
||||
arguments use owning std::string to prevent dangling references.
|
||||
|
||||
Set ``deferred=False`` only for actions that complete synchronously
|
||||
Set ``synchronous=True`` only for actions that complete synchronously
|
||||
and never store trigger arguments for later execution. This allows
|
||||
the code generator to use non-owning StringRef for zero-copy access.
|
||||
"""
|
||||
return ACTION_REGISTRY.register(name, action_type, schema, deferred=deferred)
|
||||
return ACTION_REGISTRY.register(name, action_type, schema, synchronous=synchronous)
|
||||
|
||||
|
||||
def register_condition(name: str, condition_type: MockObjClass, schema: cv.Schema):
|
||||
@@ -383,7 +383,7 @@ async def delay_action_to_code(
|
||||
cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
|
||||
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def if_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -412,7 +412,7 @@ async def if_action_to_code(
|
||||
cv.Required(CONF_THEN): validate_action_list,
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def while_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -436,7 +436,7 @@ async def while_action_to_code(
|
||||
cv.Required(CONF_THEN): validate_action_list,
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def repeat_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -481,7 +481,7 @@ async def wait_until_action_to_code(
|
||||
return var
|
||||
|
||||
|
||||
@register_action("lambda", LambdaAction, cv.lambda_, deferred=False)
|
||||
@register_action("lambda", LambdaAction, cv.lambda_, synchronous=True)
|
||||
async def lambda_action_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
@@ -500,7 +500,7 @@ async def lambda_action_to_code(
|
||||
cv.Required(CONF_ID): cv.use_id(cg.PollingComponent),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def component_update_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -520,7 +520,7 @@ async def component_update_action_to_code(
|
||||
cv.Required(CONF_ID): cv.use_id(cg.PollingComponent),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def component_suspend_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -543,7 +543,7 @@ async def component_suspend_action_to_code(
|
||||
),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def component_resume_action_to_code(
|
||||
config: ConfigType,
|
||||
@@ -602,16 +602,17 @@ async def build_condition_list(
|
||||
|
||||
|
||||
def has_deferred_actions(actions: ConfigType) -> bool:
|
||||
"""Check if a validated action list contains any deferred actions.
|
||||
"""Check if a validated action list contains any non-synchronous actions.
|
||||
|
||||
Deferred actions (delay, wait_until, script.wait) store trigger args
|
||||
for later execution, making non-owning types like StringRef unsafe.
|
||||
Non-synchronous actions (delay, wait_until, script.wait, etc.) store
|
||||
trigger args for later execution, making non-owning types like StringRef
|
||||
unsafe. Actions that haven't been audited default to non-synchronous.
|
||||
"""
|
||||
if isinstance(actions, list):
|
||||
return any(has_deferred_actions(item) for item in actions)
|
||||
if isinstance(actions, dict):
|
||||
for key in actions:
|
||||
if key in ACTION_REGISTRY and ACTION_REGISTRY[key].deferred:
|
||||
if key in ACTION_REGISTRY and not ACTION_REGISTRY[key].synchronous:
|
||||
return True
|
||||
return any(
|
||||
has_deferred_actions(v)
|
||||
|
||||
@@ -380,15 +380,17 @@ async def to_code(config: ConfigType) -> None:
|
||||
if is_optional:
|
||||
func_args.append((cg.bool_, "return_response"))
|
||||
|
||||
# Check if action chain has deferred actions that would make
|
||||
# Check if action chain has non-synchronous actions that would make
|
||||
# non-owning StringRef dangle (rx_buf_ reused after delay)
|
||||
has_deferred = automation.has_deferred_actions(conf.get(CONF_THEN, []))
|
||||
has_non_synchronous = automation.has_deferred_actions(
|
||||
conf.get(CONF_THEN, [])
|
||||
)
|
||||
|
||||
service_arg_names: list[str] = []
|
||||
for name, var_ in conf[CONF_VARIABLES].items():
|
||||
native = SERVICE_ARG_NATIVE_TYPES[var_]
|
||||
# Fall back to std::string for string args if deferred actions exist
|
||||
if has_deferred and native is cg.StringRef:
|
||||
# Fall back to std::string for string args if non-synchronous actions exist
|
||||
if has_non_synchronous and native is cg.StringRef:
|
||||
native = cg.std_string
|
||||
service_template_args.append(native)
|
||||
func_args.append((native, name))
|
||||
@@ -516,13 +518,13 @@ HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
||||
"homeassistant.action",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"homeassistant.service",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def homeassistant_service_to_code(
|
||||
config: ConfigType,
|
||||
@@ -613,7 +615,7 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema(
|
||||
"homeassistant.event",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_EVENT_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def homeassistant_event_to_code(config, action_id, template_arg, args):
|
||||
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
||||
@@ -654,7 +656,7 @@ HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
"homeassistant.tag_scanned",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
|
||||
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
||||
|
||||
@@ -124,7 +124,7 @@ BUTTON_PRESS_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"button.press", PressAction, BUTTON_PRESS_SCHEMA, deferred=False
|
||||
"button.press", PressAction, BUTTON_PRESS_SCHEMA, synchronous=True
|
||||
)
|
||||
async def button_press_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -249,7 +249,7 @@ COVER_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.open", OpenAction, COVER_ACTION_SCHEMA, deferred=False
|
||||
"cover.open", OpenAction, COVER_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_open_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -257,7 +257,7 @@ async def cover_open_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.close", CloseAction, COVER_ACTION_SCHEMA, deferred=False
|
||||
"cover.close", CloseAction, COVER_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_close_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -265,7 +265,7 @@ async def cover_close_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.stop", StopAction, COVER_ACTION_SCHEMA, deferred=False
|
||||
"cover.stop", StopAction, COVER_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_stop_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -273,7 +273,7 @@ async def cover_stop_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.toggle", ToggleAction, COVER_ACTION_SCHEMA, deferred=False
|
||||
"cover.toggle", ToggleAction, COVER_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_toggle_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -292,7 +292,7 @@ COVER_CONTROL_ACTION_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA, deferred=False
|
||||
"cover.control", ControlAction, COVER_CONTROL_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def cover_control_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -312,7 +312,7 @@ FAN_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fan.toggle", ToggleAction, FAN_ACTION_SCHEMA, deferred=False
|
||||
"fan.toggle", ToggleAction, FAN_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def fan_toggle_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -320,7 +320,7 @@ async def fan_toggle_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"fan.turn_off", TurnOffAction, FAN_ACTION_SCHEMA, deferred=False
|
||||
"fan.turn_off", TurnOffAction, FAN_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def fan_turn_off_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -340,7 +340,7 @@ async def fan_turn_off_to_code(config, action_id, template_arg, args):
|
||||
),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def fan_turn_on_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -102,7 +102,7 @@ async def to_code(config):
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.string_strict),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def globals_set_to_code(config, action_id, template_arg, args):
|
||||
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
|
||||
|
||||
@@ -51,7 +51,7 @@ from .types import (
|
||||
),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def light_toggle_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -112,13 +112,13 @@ LIGHT_TURN_ON_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"light.turn_off", LightControlAction, LIGHT_TURN_OFF_ACTION_SCHEMA, deferred=False
|
||||
"light.turn_off", LightControlAction, LIGHT_TURN_OFF_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
@automation.register_action(
|
||||
"light.turn_on", LightControlAction, LIGHT_TURN_ON_ACTION_SCHEMA, deferred=False
|
||||
"light.turn_on", LightControlAction, LIGHT_TURN_ON_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
@automation.register_action(
|
||||
"light.control", LightControlAction, LIGHT_CONTROL_ACTION_SCHEMA, deferred=False
|
||||
"light.control", LightControlAction, LIGHT_CONTROL_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def light_control_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -197,7 +197,7 @@ LIGHT_DIM_RELATIVE_ACTION_SCHEMA = cv.Schema(
|
||||
"light.dim_relative",
|
||||
DimRelativeAction,
|
||||
LIGHT_DIM_RELATIVE_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def light_dim_relative_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -519,7 +519,7 @@ LOGGER_LOG_ACTION_SCHEMA = cv.All(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
CONF_LOGGER_LOG, LambdaAction, LOGGER_LOG_ACTION_SCHEMA, deferred=False
|
||||
CONF_LOGGER_LOG, LambdaAction, LOGGER_LOG_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def logger_log_action_to_code(config, action_id, template_arg, args):
|
||||
esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
|
||||
|
||||
@@ -492,7 +492,7 @@ MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"mqtt.publish", MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA, deferred=False
|
||||
"mqtt.publish", MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def mqtt_publish_action_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -524,7 +524,7 @@ MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema(
|
||||
"mqtt.publish_json",
|
||||
MQTTPublishJsonAction,
|
||||
MQTT_PUBLISH_JSON_ACTION_SCHEMA,
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def mqtt_publish_json_action_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -347,7 +347,7 @@ OPERATION_BASE_SCHEMA = cv.Schema(
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.float_),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def number_set_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -370,7 +370,7 @@ async def number_set_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"number.decrement",
|
||||
@@ -385,7 +385,7 @@ async def number_set_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"number.to_min",
|
||||
@@ -399,7 +399,7 @@ async def number_set_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"number.to_max",
|
||||
@@ -413,7 +413,7 @@ async def number_set_to_code(config, action_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"number.operation",
|
||||
@@ -426,7 +426,7 @@ async def number_set_to_code(config, action_id, template_arg, args):
|
||||
cv.Optional(CONF_CYCLE, default=True): cv.templatable(cv.boolean),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def number_to_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -75,7 +75,7 @@ BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"output.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA, deferred=False
|
||||
"output.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def output_turn_on_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -83,7 +83,7 @@ async def output_turn_on_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"output.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA, deferred=False
|
||||
"output.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def output_turn_off_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -99,7 +99,7 @@ async def output_turn_off_to_code(config, action_id, template_arg, args):
|
||||
cv.Required(CONF_LEVEL): cv.templatable(cv.percentage),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def output_set_level_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -160,7 +160,7 @@ async def to_code(config):
|
||||
cv.Optional(validate_parameter_name): cv.templatable(cv.valid),
|
||||
},
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def script_execute_action_to_code(config, action_id, template_arg, args):
|
||||
def convert(type: str):
|
||||
@@ -209,7 +209,7 @@ async def script_execute_action_to_code(config, action_id, template_arg, args):
|
||||
"script.stop",
|
||||
ScriptStopAction,
|
||||
maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def script_stop_action_to_code(config, action_id, template_arg, args):
|
||||
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
|
||||
|
||||
@@ -145,7 +145,7 @@ OPERATION_BASE_SCHEMA = cv.Schema(
|
||||
cv.Required(CONF_OPTION): cv.templatable(cv.string_strict),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def select_set_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -163,7 +163,7 @@ async def select_set_to_code(config, action_id, template_arg, args):
|
||||
cv.Required(CONF_INDEX): cv.templatable(cv.positive_int),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def select_set_index_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -219,7 +219,7 @@ async def select_is_to_code(config, condition_id, template_arg, args):
|
||||
cv.Optional(CONF_CYCLE, default=True): cv.templatable(cv.boolean),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"select.next",
|
||||
@@ -232,7 +232,7 @@ async def select_is_to_code(config, condition_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"select.previous",
|
||||
@@ -247,7 +247,7 @@ async def select_is_to_code(config, condition_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"select.first",
|
||||
@@ -259,7 +259,7 @@ async def select_is_to_code(config, condition_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
@automation.register_action(
|
||||
"select.last",
|
||||
@@ -271,7 +271,7 @@ async def select_is_to_code(config, condition_id, template_arg, args):
|
||||
}
|
||||
)
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def select_operation_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -198,7 +198,7 @@ SWITCH_CONTROL_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"switch.control", ControlAction, SWITCH_CONTROL_ACTION_SCHEMA, deferred=False
|
||||
"switch.control", ControlAction, SWITCH_CONTROL_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def switch_control_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
@@ -209,13 +209,13 @@ async def switch_control_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"switch.toggle", ToggleAction, SWITCH_ACTION_SCHEMA, deferred=False
|
||||
"switch.toggle", ToggleAction, SWITCH_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
@automation.register_action(
|
||||
"switch.turn_off", TurnOffAction, SWITCH_ACTION_SCHEMA, deferred=False
|
||||
"switch.turn_off", TurnOffAction, SWITCH_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
@automation.register_action(
|
||||
"switch.turn_on", TurnOnAction, SWITCH_ACTION_SCHEMA, deferred=False
|
||||
"switch.turn_on", TurnOnAction, SWITCH_ACTION_SCHEMA, synchronous=True
|
||||
)
|
||||
async def switch_toggle_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
@@ -164,7 +164,7 @@ OPERATION_BASE_SCHEMA = cv.Schema(
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.string_strict),
|
||||
}
|
||||
),
|
||||
deferred=False,
|
||||
synchronous=True,
|
||||
)
|
||||
async def text_set_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
|
||||
+6
-4
@@ -25,13 +25,13 @@ class RegistryEntry:
|
||||
type_id: "MockObjClass",
|
||||
schema: "Schema",
|
||||
*,
|
||||
deferred: bool = True,
|
||||
synchronous: bool = False,
|
||||
):
|
||||
self.name = name
|
||||
self.fun = fun
|
||||
self.type_id = type_id
|
||||
self.raw_schema = schema
|
||||
self.deferred = deferred
|
||||
self.synchronous = synchronous
|
||||
|
||||
@property
|
||||
def coroutine_fun(self):
|
||||
@@ -58,10 +58,12 @@ class Registry(dict[str, RegistryEntry]):
|
||||
type_id: "MockObjClass",
|
||||
schema: "Schema",
|
||||
*,
|
||||
deferred: bool = True,
|
||||
synchronous: bool = False,
|
||||
):
|
||||
def decorator(fun: Callable[..., Any]):
|
||||
self[name] = RegistryEntry(name, fun, type_id, schema, deferred=deferred)
|
||||
self[name] = RegistryEntry(
|
||||
name, fun, type_id, schema, synchronous=synchronous
|
||||
)
|
||||
return fun
|
||||
|
||||
return decorator
|
||||
|
||||
@@ -9,25 +9,25 @@ from esphome.automation import has_deferred_actions
|
||||
from esphome.util import RegistryEntry
|
||||
|
||||
|
||||
def _make_registry(deferred_actions: set[str]) -> dict[str, RegistryEntry]:
|
||||
"""Create a mock ACTION_REGISTRY with specified deferred actions.
|
||||
def _make_registry(non_synchronous_actions: set[str]) -> dict[str, RegistryEntry]:
|
||||
"""Create a mock ACTION_REGISTRY with specified non-synchronous actions.
|
||||
|
||||
Uses the default deferred=True, matching the real registry behavior.
|
||||
Uses the default synchronous=False, matching the real registry behavior.
|
||||
"""
|
||||
registry: dict[str, RegistryEntry] = {}
|
||||
for name in deferred_actions:
|
||||
for name in non_synchronous_actions:
|
||||
registry[name] = RegistryEntry(name, lambda: None, None, None)
|
||||
return registry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_registry() -> Generator[dict[str, RegistryEntry]]:
|
||||
"""Fixture that patches ACTION_REGISTRY with delay, wait_until, script.wait as deferred."""
|
||||
"""Fixture that patches ACTION_REGISTRY with delay, wait_until, script.wait as non-synchronous."""
|
||||
registry: dict[str, RegistryEntry] = _make_registry(
|
||||
{"delay", "wait_until", "script.wait"}
|
||||
)
|
||||
registry["logger.log"] = RegistryEntry(
|
||||
"logger.log", lambda: None, None, None, deferred=False
|
||||
"logger.log", lambda: None, None, None, synchronous=True
|
||||
)
|
||||
with patch("esphome.automation.ACTION_REGISTRY", registry):
|
||||
yield registry
|
||||
@@ -82,10 +82,10 @@ def test_has_deferred_actions_unknown_not_in_registry(
|
||||
assert has_deferred_actions([{"unknown.action": "value"}]) is False
|
||||
|
||||
|
||||
def test_has_deferred_actions_default_deferred(
|
||||
def test_has_deferred_actions_default_non_synchronous(
|
||||
mock_registry: dict[str, RegistryEntry],
|
||||
) -> None:
|
||||
"""Actions registered without explicit deferred=False default to deferred=True."""
|
||||
"""Actions registered without explicit synchronous=True default to non-synchronous."""
|
||||
mock_registry["some.action"] = RegistryEntry(
|
||||
"some.action", lambda: None, None, None
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user