From f6bf6bd8ee0aff23bbc1961bac67e7d8beb52121 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 8 Nov 2025 21:12:00 -0600 Subject: [PATCH 1/2] [uart] Store static data in flash and use function pointers for lambdas --- esphome/components/uart/__init__.py | 7 ++++-- esphome/components/uart/automation.h | 32 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index eb911ed007..cbc11d0db0 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -31,7 +31,7 @@ from esphome.const import ( PLATFORM_HOST, PlatformFramework, ) -from esphome.core import CORE +from esphome.core import CORE, ID import esphome.final_validate as fv from esphome.yaml_util import make_data_base @@ -446,7 +446,10 @@ async def uart_write_to_code(config, action_id, template_arg, args): templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) cg.add(var.set_data_template(templ)) else: - cg.add(var.set_data_static(cg.ArrayInitializer(*data))) + # Generate static array in flash to avoid RAM copy + arr_id = ID(f"{action_id}_data", is_declaration=True, type=cg.uint8) + arr = cg.static_const_array(arr_id, cg.ArrayInitializer(*data)) + cg.add(var.set_data_static(arr, len(data))) return var diff --git a/esphome/components/uart/automation.h b/esphome/components/uart/automation.h index ad2c4d2bf1..7a3344c2f1 100644 --- a/esphome/components/uart/automation.h +++ b/esphome/components/uart/automation.h @@ -10,32 +10,38 @@ namespace uart { template class UARTWriteAction : public Action, public Parented { public: - void set_data_template(std::function(Ts...)> func) { - this->data_func_ = func; + void set_data_template(std::vector (*func)(Ts...)) { + // Stateless lambdas (generated by ESPHome) implicitly convert to function pointers + this->data_.func = func; this->static_ = false; } - void set_data_static(std::vector &&data) { - this->data_static_ = std::move(data); - this->static_ = true; - } - void set_data_static(std::initializer_list data) { - this->data_static_ = std::vector(data); + + // Store pointer to static data in flash (no RAM copy) + void set_data_static(const uint8_t *data, size_t len) { + // Simply set pointer and length - no construction needed for POD types + this->data_.static_data.ptr = data; + this->data_.static_data.len = len; this->static_ = true; } void play(const Ts &...x) override { if (this->static_) { - this->parent_->write_array(this->data_static_); + this->parent_->write_array(this->data_.static_data.ptr, this->data_.static_data.len); } else { - auto val = this->data_func_(x...); + auto val = this->data_.func(x...); this->parent_->write_array(val); } } protected: - bool static_{false}; - std::function(Ts...)> data_func_{}; - std::vector data_static_{}; + bool static_{true}; // Default to static mode (most common case) + union Data { + std::vector (*func)(Ts...); // Function pointer (stateless lambdas) + struct { + const uint8_t *ptr; + size_t len; + } static_data; + } data_; }; } // namespace uart From c5014321a6e0d10eeda7d1b7ae861b1774e33a19 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 8 Nov 2025 21:15:28 -0600 Subject: [PATCH 2/2] Expand uart.write tests --- tests/components/uart/test.esp32-idf.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/components/uart/test.esp32-idf.yaml b/tests/components/uart/test.esp32-idf.yaml index 9744a48409..6ffd0d7282 100644 --- a/tests/components/uart/test.esp32-idf.yaml +++ b/tests/components/uart/test.esp32-idf.yaml @@ -3,6 +3,8 @@ esphome: then: - uart.write: 'Hello World' - uart.write: [0x00, 0x20, 0x42] + - uart.write: !lambda |- + return {0xAA, 0xBB, 0xCC}; uart: - id: uart_uart @@ -46,6 +48,15 @@ switch: turn_on: "TURN_ON" turn_off: "TURN_OFF" +number: + - platform: template + name: "Test Number" + id: test_number + optimistic: true + min_value: 0 + max_value: 100 + step: 1 + button: # Test uart button with array data - platform: uart @@ -57,3 +68,10 @@ button: name: "UART Button String" uart_id: uart_uart data: "BUTTON_PRESS" + # Test uart button with lambda (function pointer) + - platform: template + name: "UART Lambda Test" + on_press: + - uart.write: !lambda |- + std::string cmd = "VALUE=" + str_sprintf("%.0f", id(test_number).state) + "\r\n"; + return std::vector(cmd.begin(), cmd.end());