diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 7a9518687bf..d3831440c56 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -343,21 +343,26 @@ void APIConnection::on_disconnect_response() { this->flags_.remove = true; } -// Non-template helper to fill common entity info fields. -// Caller provides buffers that must remain alive until encoding completes. -void APIConnection::fill_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, APIConnection *conn, - std::span object_id_buf -#ifdef USE_ENTITY_ICON - , - std::span icon_buf +uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, + uint32_t calculated_size, MessageEncodeFn encode_fn, + APIConnection *conn, uint32_t remaining_size) { + msg.key = entity->get_object_id_hash(); +#ifdef USE_DEVICES + msg.device_id = entity->get_device_id(); #endif -) { + return encode_to_buffer_(calculated_size, encode_fn, &msg, conn, remaining_size); +} + +uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, + uint32_t calculated_size, MessageEncodeFn encode_fn, + APIConnection *conn, uint32_t remaining_size) { msg.key = entity->get_object_id_hash(); // API 1.14+ clients compute object_id client-side from the entity name // For older clients, we must send object_id for backward compatibility // See: https://github.com/esphome/backlog/issues/76 // TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then + char object_id_buf[OBJECT_ID_MAX_LEN]; if (!conn->client_supports_api_version(1, 14)) { msg.object_id = entity->get_object_id_to(object_id_buf); } @@ -367,6 +372,7 @@ void APIConnection::fill_entity_info_(EntityBase *entity, InfoResponseProtoMessa } #ifdef USE_ENTITY_ICON + char icon_buf[MAX_ICON_LENGTH]; msg.icon = StringRef(entity->get_icon_to(icon_buf)); #endif msg.disabled_by_default = entity->is_disabled_by_default(); @@ -374,6 +380,15 @@ void APIConnection::fill_entity_info_(EntityBase *entity, InfoResponseProtoMessa #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif + return encode_to_buffer_(calculated_size, encode_fn, &msg, conn, remaining_size); +} + +uint16_t APIConnection::fill_and_encode_entity_info_with_device_class_( + EntityBase *entity, InfoResponseProtoMessage &msg, StringRef &device_class_field, uint32_t calculated_size, + MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { + char dc_buf[MAX_DEVICE_CLASS_LENGTH]; + device_class_field = StringRef(entity->get_device_class_to(dc_buf)); + return fill_and_encode_entity_info_(entity, msg, calculated_size, encode_fn, conn, remaining_size); } #ifdef USE_BINARY_SENSOR diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 21948ba2470..99e5c2ee72d 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -346,49 +346,43 @@ class APIConnection final : public APIServerConnectionBase { return encode_to_buffer_(calculated_size_of(msg), &encode_msg_, &msg, conn, remaining_size); } - // Helper to fill entity state base and encode message + // Non-template core — fills state fields and encodes + static uint16_t fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, + uint32_t calculated_size, MessageEncodeFn encode_fn, + APIConnection *conn, uint32_t remaining_size); + + // Thin template wrapper template static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - msg.key = entity->get_object_id_hash(); -#ifdef USE_DEVICES - msg.device_id = entity->get_device_id(); -#endif - return encode_message_to_buffer(msg, conn, remaining_size); + return fill_and_encode_entity_state_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); } - // Non-template helper to fill common entity info fields. - // Caller provides buffers that must remain alive until encoding completes. - static void fill_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, APIConnection *conn, - std::span object_id_buf -#ifdef USE_ENTITY_ICON - , - std::span icon_buf -#endif - ); + // Non-template core — fills info fields, allocates buffers, and encodes + static uint16_t fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, + uint32_t calculated_size, MessageEncodeFn encode_fn, APIConnection *conn, + uint32_t remaining_size); - // Template to fill entity info and encode + // Thin template wrapper template static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - char object_id_buf[OBJECT_ID_MAX_LEN]; -#ifdef USE_ENTITY_ICON - char icon_buf[MAX_ICON_LENGTH]; - fill_entity_info_(entity, msg, conn, object_id_buf, icon_buf); -#else - fill_entity_info_(entity, msg, conn, object_id_buf); -#endif - return encode_message_to_buffer(msg, conn, remaining_size); + return fill_and_encode_entity_info_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); } - // Wrapper for entity types that have a device_class field + // Non-template core — fills device_class, then delegates to fill_and_encode_entity_info_ + static uint16_t fill_and_encode_entity_info_with_device_class_(EntityBase *entity, InfoResponseProtoMessage &msg, + StringRef &device_class_field, + uint32_t calculated_size, MessageEncodeFn encode_fn, + APIConnection *conn, uint32_t remaining_size); + + // Thin template wrapper template static uint16_t fill_and_encode_entity_info_with_device_class(EntityBase *entity, T &msg, StringRef &device_class_field, APIConnection *conn, uint32_t remaining_size) { - char dc_buf[MAX_DEVICE_CLASS_LENGTH]; - device_class_field = StringRef(entity->get_device_class_to(dc_buf)); - return fill_and_encode_entity_info(entity, msg, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, calculated_size_of(msg), + &encode_msg_, conn, remaining_size); } #ifdef USE_VOICE_ASSISTANT