[api] Register homeassistant.action with synchronous=False to fix stale trigger args in response callbacks (#17367)

This commit is contained in:
Jonathan Swoboda
2026-07-02 19:47:12 -04:00
committed by GitHub
parent 5417a16f9d
commit 9f589ec4fc
5 changed files with 106 additions and 2 deletions
@@ -0,0 +1,28 @@
"""Tests for arg-type selection of api user-defined services with homeassistant.action."""
CONFIG = "tests/component_tests/api/test_homeassistant_action.yaml"
def test_synchronous_chain_keeps_zero_copy_args(generate_main):
"""A chain of synchronous actions keeps the non-owning StringRef arg type."""
main_cpp = generate_main(CONFIG)
assert (
"api::UserServiceTrigger<api::enums::SUPPORTS_RESPONSE_NONE, StringRef>"
'("zero_copy_args", {"message"})' in main_cpp
)
def test_response_callback_args_are_owning(generate_main):
"""homeassistant.action with on_success/on_error stores the trigger args
until the HomeassistantActionResponse arrives, so string args must fall
back to owning std::string; StringRef would point into the connection's
receive buffer, which is reused before the response arrives."""
main_cpp = generate_main(CONFIG)
assert (
"api::UserServiceTrigger<api::enums::SUPPORTS_RESPONSE_NONE, std::string>"
'("response_args", {"message"})' in main_cpp
)
assert "api::HomeAssistantServiceCallAction<std::string>" in main_cpp
assert "api::HomeAssistantServiceCallAction<StringRef>" not in main_cpp
@@ -0,0 +1,43 @@
esphome:
name: test
esp32:
board: esp32dev
wifi:
ssid: SomeNetwork
password: SomePassword
logger:
api:
actions:
# Chain of synchronous actions that never store the args:
# keeps the zero-copy StringRef arg type.
- action: zero_copy_args
variables:
message: string
then:
- logger.log:
format: "%s"
args: [message.c_str()]
# homeassistant.action with on_success/on_error stores the trigger args
# until the action response arrives, so the codegen must fall back to
# owning std::string args (StringRef would dangle once the receive
# buffer is reused).
- action: response_args
variables:
message: string
then:
- homeassistant.action:
action: notify.notify
data:
message: !lambda return message;
on_success:
- logger.log:
format: "sent %s"
args: [message.c_str()]
on_error:
- logger.log:
format: "failed (%s): %s"
args: [error.c_str(), message.c_str()]