[nextion] Pass std::string to custom-protocol automations that defer (#20571)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Frédéric Metrich
2026-10-11 20:30:53 -10:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 0c645ac3a1
commit ba9061e34e
5 changed files with 109 additions and 10 deletions
+20
View File
@@ -11,6 +11,7 @@ from esphome.const import (
PLATFORM_ESP8266,
)
from esphome.core import CORE, TimePeriod
from esphome.types import ConfigType, TemplateArgsType
from . import FILTER_SOURCE_FILES, Nextion, nextion_ns, nextion_ref # noqa: F401 pylint: disable=unused-import
from .base_component import (
@@ -177,6 +178,10 @@ _CALLBACK_AUTOMATIONS = (
automation.CallbackAutomation(
CONF_ON_BUFFER_OVERFLOW, "add_buffer_overflow_event_callback"
),
)
# The strings live only while the callback runs
_CUSTOM_CALLBACK_AUTOMATIONS = (
automation.CallbackAutomation(
CONF_ON_CUSTOM_BINARY_SENSOR,
"add_custom_binary_sensor_callback",
@@ -293,3 +298,18 @@ async def to_code(config):
cg.add_define(define_name)
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
for entry in _CUSTOM_CALLBACK_AUTOMATIONS:
for conf in config.get(entry.conf_key, []):
await automation.build_callback_automation(
var, entry.callback_method, _owning_args(entry.args, conf), conf
)
def _owning_args(args: TemplateArgsType, conf: ConfigType) -> TemplateArgsType:
"""Pass std::string instead of StringRef to an automation that defers, as it keeps its arguments."""
if not automation.has_non_synchronous_actions(conf):
return args
return [
(cg.std_string if type_ is cg.StringRef else type_, name)
for type_, name in args
]
@@ -0,0 +1,21 @@
esphome:
name: test
esp32:
board: esp32dev
framework:
type: esp-idf
uart:
tx_pin: 17
rx_pin: 16
baud_rate: 115200
display:
- platform: nextion
on_custom_text_sensor:
- then:
- lambda: 'ESP_LOGD("test", "%s=%s", key.c_str(), value.c_str());'
- then:
- delay: 1s
- lambda: 'ESP_LOGD("test", "%s=%s", key.c_str(), value.c_str());'
@@ -0,0 +1,47 @@
"""Tests for the argument types of the nextion custom-protocol triggers."""
from collections.abc import Callable
from pathlib import Path
import esphome.codegen as cg
from esphome.components.nextion.display import _owning_args
from esphome.core import Lambda
ARGS = [(cg.StringRef, "key"), (cg.bool_, "value")]
SYNCHRONOUS_ACTION = {"lambda": Lambda('ESP_LOGD("test", "ran");')}
DEFERRING_ACTION = {"delay": "1s"}
TRUE_CONDITION = {"lambda": Lambda("return true;")}
def test_synchronous_automation_keeps_string_ref() -> None:
assert _owning_args(ARGS, {"then": [SYNCHRONOUS_ACTION]}) == ARGS
def test_deferring_automation_gets_std_string() -> None:
assert _owning_args(ARGS, {"then": [SYNCHRONOUS_ACTION, DEFERRING_ACTION]}) == [
(cg.std_string, "key"),
(cg.bool_, "value"),
]
def test_nested_deferring_action_gets_std_string() -> None:
actions = [{"if": {"condition": TRUE_CONDITION, "then": [DEFERRING_ACTION]}}]
assert _owning_args(ARGS, {"then": actions})[0] == (cg.std_string, "key")
def test_all_string_refs_swapped() -> None:
args = [(cg.StringRef, "key"), (cg.StringRef, "value")]
assert _owning_args(args, {"then": [DEFERRING_ACTION]}) == [
(cg.std_string, "key"),
(cg.std_string, "value"),
]
def test_generated_automation_types(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
main_cpp = generate_main(component_config_path("custom_triggers.yaml"))
assert "Automation<StringRef, StringRef>" in main_cpp
assert "Automation<std::string, std::string>" in main_cpp
+21 -10
View File
@@ -287,13 +287,20 @@ display:
then:
logger.log: "Nextion reported a buffer overflow!"
on_custom_text_sensor:
then:
- lambda: |-
// key: StringRef, value: StringRef
if (key == "csv") {
// parse value here, or forward to your own component
ESP_LOGD("nextion.csv", "Got CSV: %s", value.c_str());
}
- then:
- lambda: |-
// key: StringRef, value: StringRef
if (key == "csv") {
// parse value here, or forward to your own component
ESP_LOGD("nextion.csv", "Got CSV: %s", value.c_str());
}
# Deferring: key and value are passed as std::string
- then:
- delay: 1s
- lambda: |-
if (key == "csv") {
ESP_LOGD("nextion.csv", "Got CSV earlier: %s", value.c_str());
}
on_custom_sensor:
then:
- lambda: |-
@@ -308,9 +315,13 @@ display:
ESP_LOGD("nextion.btn", "btn1=%s", ONOFF(value));
}
on_custom_switch:
then:
- lambda: |-
ESP_LOGD("nextion.sw", "%s=%s", key.c_str(), ONOFF(value));
- then:
- lambda: |-
ESP_LOGD("nextion.sw", "%s=%s", key.c_str(), ONOFF(value));
- then:
- delay: 1s
- lambda: |-
ESP_LOGD("nextion.sw", "%s was %s", key.c_str(), ONOFF(value));
on_page:
then:
lambda: 'ESP_LOGD("display","Display shows new page %u", x);'