diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index f711502746..6254854238 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -301,9 +301,15 @@ class APIConnection final : public APIServerConnection { APIConnection *conn, uint32_t remaining_size, bool is_single) { // Set common fields that are shared by all entity types msg.key = entity->get_object_id_hash(); - // IMPORTANT: get_object_id() may return a temporary std::string - std::string object_id = entity->get_object_id(); - msg.set_object_id(StringRef(object_id)); + // Try to use static reference first to avoid allocation + StringRef static_ref = entity->get_object_id_ref_for_api_(); + if (!static_ref.empty()) { + msg.set_object_id(static_ref); + } else { + // Dynamic case - need to allocate + std::string object_id = entity->get_object_id(); + msg.set_object_id(StringRef(object_id)); + } if (entity->has_own_name()) { msg.set_name(entity->get_name()); diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 2ea9c77a3e..411a877bbf 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -1,6 +1,7 @@ #include "esphome/core/entity_base.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" +#include "esphome/core/string_ref.h" namespace esphome { @@ -50,13 +51,18 @@ std::string EntityBase::get_object_id() const { if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) { // `App.get_friendly_name()` is dynamic. return str_sanitize(str_snake_case(App.get_friendly_name())); - } else { - // `App.get_friendly_name()` is constant. - if (this->object_id_c_str_ == nullptr) { - return ""; - } - return this->object_id_c_str_; } + // `App.get_friendly_name()` is constant. + return this->object_id_c_str_ == nullptr ? "" : this->object_id_c_str_; +} +StringRef EntityBase::get_object_id_ref_for_api_() const { + static constexpr auto EMPTY_STRING = StringRef::from_lit(""); + // Return empty for dynamic case (MAC suffix) + if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) { + return EMPTY_STRING; + } + // For static case, return the string or empty if null + return this->object_id_c_str_ == nullptr ? EMPTY_STRING : StringRef(this->object_id_c_str_); } void EntityBase::set_object_id(const char *object_id) { this->object_id_c_str_ = object_id; diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index e60e0728bc..68163ce8c3 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -12,6 +12,11 @@ namespace esphome { +// Forward declaration for friend access +namespace api { +class APIConnection; +} // namespace api + enum EntityCategory : uint8_t { ENTITY_CATEGORY_NONE = 0, ENTITY_CATEGORY_CONFIG = 1, @@ -81,6 +86,12 @@ class EntityBase { void set_has_state(bool state) { this->flags_.has_state = state; } protected: + friend class api::APIConnection; + + // Get object_id as StringRef when it's static (for API usage) + // Returns empty StringRef if object_id is dynamic (needs allocation) + StringRef get_object_id_ref_for_api_() const; + /// The hash_base() function has been deprecated. It is kept in this /// class for now, to prevent external components from not compiling. virtual uint32_t hash_base() { return 0L; }