From 0610b3a60af4f4ea51cb4e38acc12ece4552a3a1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Dec 2025 23:49:09 -0600 Subject: [PATCH 1/6] [text] Store pattern as const char* to reduce memory usage --- esphome/components/template/text/template_text.cpp | 2 +- esphome/components/text/text_traits.h | 9 ++++----- esphome/components/web_server/web_server.cpp | 2 +- esphome/components/web_server/web_server_v1.cpp | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/components/template/text/template_text.cpp b/esphome/components/template/text/template_text.cpp index a917c72a141..7baed6cb205 100644 --- a/esphome/components/template/text/template_text.cpp +++ b/esphome/components/template/text/template_text.cpp @@ -16,7 +16,7 @@ void TemplateText::setup() { uint32_t key = this->get_preference_hash(); key += this->traits.get_min_length() << 2; key += this->traits.get_max_length() << 4; - key += fnv1_hash(this->traits.get_pattern()) << 6; + key += fnv1_hash(this->traits.get_pattern_ref().c_str()) << 6; this->pref_->setup(key, value); } if (!value.empty()) diff --git a/esphome/components/text/text_traits.h b/esphome/components/text/text_traits.h index ceaba2deadf..f182a7721e5 100644 --- a/esphome/components/text/text_traits.h +++ b/esphome/components/text/text_traits.h @@ -1,8 +1,7 @@ #pragma once -#include +#include -#include "esphome/core/helpers.h" #include "esphome/core/string_ref.h" namespace esphome { @@ -22,8 +21,8 @@ class TextTraits { int get_max_length() const { return this->max_length_; } // Set/get the pattern. - void set_pattern(std::string pattern) { this->pattern_ = std::move(pattern); } - std::string get_pattern() const { return this->pattern_; } + void set_pattern(const char *pattern) { this->pattern_ = pattern; } + std::string get_pattern() const { return std::string(this->pattern_); } StringRef get_pattern_ref() const { return StringRef(this->pattern_); } // Set/get the frontend mode. @@ -33,7 +32,7 @@ class TextTraits { protected: int min_length_; int max_length_; - std::string pattern_; + const char *pattern_{""}; TextMode mode_{TEXT_MODE_TEXT}; }; diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 1f3605a0824..ff37f5ea036 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1211,7 +1211,7 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json set_json_icon_state_value(root, obj, "text", state, value, start_config); root[ESPHOME_F("min_length")] = obj->traits.get_min_length(); root[ESPHOME_F("max_length")] = obj->traits.get_max_length(); - root[ESPHOME_F("pattern")] = obj->traits.get_pattern(); + root[ESPHOME_F("pattern")] = obj->traits.get_pattern_ref(); if (start_config == DETAIL_ALL) { root[ESPHOME_F("mode")] = (int) obj->traits.get_mode(); this->add_sorting_info_(root, obj); diff --git a/esphome/components/web_server/web_server_v1.cpp b/esphome/components/web_server/web_server_v1.cpp index 870a338620b..d46476a8708 100644 --- a/esphome/components/web_server/web_server_v1.cpp +++ b/esphome/components/web_server/web_server_v1.cpp @@ -142,7 +142,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream.print(R"(" maxlength=")"); stream.print(text->traits.get_max_length()); stream.print(R"(" pattern=")"); - stream.print(text->traits.get_pattern().c_str()); + stream.print(text->traits.get_pattern_ref().c_str()); stream.print(R"(" value=")"); stream.print(text->state.c_str()); stream.print(R"("/>)"); From 789faca7c4b19ee52c8f93b0d06cfdc1b637a03a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Dec 2025 23:50:48 -0600 Subject: [PATCH 2/6] [text] Store pattern as const char* to reduce memory usage --- tests/integration/fixtures/api_message_size_batching.yaml | 1 + tests/integration/test_api_message_size_batching.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tests/integration/fixtures/api_message_size_batching.yaml b/tests/integration/fixtures/api_message_size_batching.yaml index c730dc1aa31..0fed311e633 100644 --- a/tests/integration/fixtures/api_message_size_batching.yaml +++ b/tests/integration/fixtures/api_message_size_batching.yaml @@ -143,6 +143,7 @@ text: mode: text min_length: 0 max_length: 255 + pattern: "[A-Za-z0-9 ]+" initial_value: "Initial value" update_interval: 5.0s diff --git a/tests/integration/test_api_message_size_batching.py b/tests/integration/test_api_message_size_batching.py index f7859eb9027..5b123318c41 100644 --- a/tests/integration/test_api_message_size_batching.py +++ b/tests/integration/test_api_message_size_batching.py @@ -141,6 +141,9 @@ async def test_api_message_size_batching( assert text_input.max_length == 255, ( f"Expected max_length 255, got {text_input.max_length}" ) + assert text_input.pattern == "[A-Za-z0-9 ]+", ( + f"Expected pattern '[A-Za-z0-9 ]+', got '{text_input.pattern}'" + ) # Verify total entity count - messages of various sizes were batched successfully # We have: 3 selects + 3 text sensors + 1 text input + 1 number = 8 total From e63673f5efb4e2ed9d44fb42f7c3f3fda5f878ce Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Dec 2025 23:55:15 -0600 Subject: [PATCH 3/6] [text] Store pattern as const char* to reduce memory usage --- esphome/components/template/text/template_text.cpp | 2 +- esphome/components/text/text_traits.h | 1 + esphome/components/web_server/web_server_v1.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/template/text/template_text.cpp b/esphome/components/template/text/template_text.cpp index 7baed6cb205..7244ad7c298 100644 --- a/esphome/components/template/text/template_text.cpp +++ b/esphome/components/template/text/template_text.cpp @@ -16,7 +16,7 @@ void TemplateText::setup() { uint32_t key = this->get_preference_hash(); key += this->traits.get_min_length() << 2; key += this->traits.get_max_length() << 4; - key += fnv1_hash(this->traits.get_pattern_ref().c_str()) << 6; + key += fnv1_hash(this->traits.get_pattern_c_str()) << 6; this->pref_->setup(key, value); } if (!value.empty()) diff --git a/esphome/components/text/text_traits.h b/esphome/components/text/text_traits.h index f182a7721e5..473daafb8eb 100644 --- a/esphome/components/text/text_traits.h +++ b/esphome/components/text/text_traits.h @@ -23,6 +23,7 @@ class TextTraits { // Set/get the pattern. void set_pattern(const char *pattern) { this->pattern_ = pattern; } std::string get_pattern() const { return std::string(this->pattern_); } + const char *get_pattern_c_str() const { return this->pattern_; } StringRef get_pattern_ref() const { return StringRef(this->pattern_); } // Set/get the frontend mode. diff --git a/esphome/components/web_server/web_server_v1.cpp b/esphome/components/web_server/web_server_v1.cpp index d46476a8708..486c38a2abc 100644 --- a/esphome/components/web_server/web_server_v1.cpp +++ b/esphome/components/web_server/web_server_v1.cpp @@ -142,7 +142,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) { stream.print(R"(" maxlength=")"); stream.print(text->traits.get_max_length()); stream.print(R"(" pattern=")"); - stream.print(text->traits.get_pattern_ref().c_str()); + stream.print(text->traits.get_pattern_c_str()); stream.print(R"(" value=")"); stream.print(text->state.c_str()); stream.print(R"("/>)"); From 188148546e2d37863226866d18d28951d7415b0b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 6 Dec 2025 23:55:38 -0600 Subject: [PATCH 4/6] [text] Store pattern as const char* to reduce memory usage --- esphome/components/web_server/web_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index ff37f5ea036..ca3aa21a958 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -1211,7 +1211,7 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json set_json_icon_state_value(root, obj, "text", state, value, start_config); root[ESPHOME_F("min_length")] = obj->traits.get_min_length(); root[ESPHOME_F("max_length")] = obj->traits.get_max_length(); - root[ESPHOME_F("pattern")] = obj->traits.get_pattern_ref(); + root[ESPHOME_F("pattern")] = obj->traits.get_pattern_c_str(); if (start_config == DETAIL_ALL) { root[ESPHOME_F("mode")] = (int) obj->traits.get_mode(); this->add_sorting_info_(root, obj); From d881e6055eac33c95cdd25aba867b834a6c32b5a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 7 Dec 2025 10:31:33 -0600 Subject: [PATCH 5/6] tweak --- esphome/components/api/api_connection.cpp | 2 +- esphome/components/text/text_traits.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index f0428546de9..0a0435e25bb 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -866,7 +866,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co msg.mode = static_cast(text->traits.get_mode()); msg.min_length = text->traits.get_min_length(); msg.max_length = text->traits.get_max_length(); - msg.set_pattern(text->traits.get_pattern_ref()); + msg.set_pattern(text->traits.get_pattern_c_str()); return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } diff --git a/esphome/components/text/text_traits.h b/esphome/components/text/text_traits.h index 473daafb8eb..d8690977000 100644 --- a/esphome/components/text/text_traits.h +++ b/esphome/components/text/text_traits.h @@ -2,8 +2,6 @@ #include -#include "esphome/core/string_ref.h" - namespace esphome { namespace text { @@ -24,7 +22,6 @@ class TextTraits { void set_pattern(const char *pattern) { this->pattern_ = pattern; } std::string get_pattern() const { return std::string(this->pattern_); } const char *get_pattern_c_str() const { return this->pattern_; } - StringRef get_pattern_ref() const { return StringRef(this->pattern_); } // Set/get the frontend mode. void set_mode(TextMode mode) { this->mode_ = mode; } From 475ce1f3fa80626f31aa7c37e03e3dc05273efec Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 7 Dec 2025 12:43:02 -0600 Subject: [PATCH 6/6] tweaks --- esphome/components/api/api_connection.cpp | 2 +- esphome/components/text/text_traits.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 0a0435e25bb..f0428546de9 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -866,7 +866,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co msg.mode = static_cast(text->traits.get_mode()); msg.min_length = text->traits.get_min_length(); msg.max_length = text->traits.get_max_length(); - msg.set_pattern(text->traits.get_pattern_c_str()); + msg.set_pattern(text->traits.get_pattern_ref()); return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } diff --git a/esphome/components/text/text_traits.h b/esphome/components/text/text_traits.h index d8690977000..473daafb8eb 100644 --- a/esphome/components/text/text_traits.h +++ b/esphome/components/text/text_traits.h @@ -2,6 +2,8 @@ #include +#include "esphome/core/string_ref.h" + namespace esphome { namespace text { @@ -22,6 +24,7 @@ class TextTraits { void set_pattern(const char *pattern) { this->pattern_ = pattern; } std::string get_pattern() const { return std::string(this->pattern_); } const char *get_pattern_c_str() const { return this->pattern_; } + StringRef get_pattern_ref() const { return StringRef(this->pattern_); } // Set/get the frontend mode. void set_mode(TextMode mode) { this->mode_ = mode; }