From c639accdfd3572e2b3aa078e15767b2311c5f1c2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 11:55:26 -1000 Subject: [PATCH 01/42] move ICON_MAX_LENGTH to esphome/core/config.py alongside other max length constants --- esphome/config_validation.py | 7 ++----- esphome/core/config.py | 4 ++++ esphome/core/entity_helpers.py | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 368b4f9f4a9..1eac53e9b20 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -398,13 +398,10 @@ def string_strict(value): ) -# Max icon string length (63 chars + null = 64-byte PROGMEM buffer) -# Keep in sync with MAX_ICON_LENGTH in esphome/core/entity_base.h -ICON_MAX_LENGTH = 63 - - def icon(value): """Validate that a given config value is a valid icon.""" + from esphome.core.config import ICON_MAX_LENGTH + value = string_strict(value) if not value: return value diff --git a/esphome/core/config.py b/esphome/core/config.py index 9411949bb92..cde2d280a49 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -188,6 +188,10 @@ else: # Keep in sync with ESPHOME_FRIENDLY_NAME_MAX_LEN in esphome/core/entity_base.h FRIENDLY_NAME_MAX_LEN = 120 +# Max icon string length (63 chars + null = 64-byte PROGMEM buffer) +# Keep in sync with MAX_ICON_LENGTH in esphome/core/entity_base.h +ICON_MAX_LENGTH = 63 + AREA_SCHEMA = cv.Schema( { cv.GenerateID(CONF_ID): cv.declare_id(Area), diff --git a/esphome/core/entity_helpers.py b/esphome/core/entity_helpers.py index a8ca2f74324..01fa27b833a 100644 --- a/esphome/core/entity_helpers.py +++ b/esphome/core/entity_helpers.py @@ -17,6 +17,7 @@ from esphome.const import ( CONF_UNIT_OF_MEASUREMENT, ) from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority +from esphome.core.config import ICON_MAX_LENGTH from esphome.cpp_generator import MockObj, RawStatement, add, get_variable import esphome.final_validate as fv from esphome.helpers import cpp_string_escape, fnv1_hash_object_id, sanitize, snake_case @@ -190,9 +191,9 @@ def register_unit_of_measurement(value: str) -> int: def register_icon(value: str) -> int: """Register an icon string and return its 1-based index.""" - if value and len(value) > cv.ICON_MAX_LENGTH: + if value and len(value) > ICON_MAX_LENGTH: raise ValueError( - f"Icon string too long ({len(value)} chars, max {cv.ICON_MAX_LENGTH}): '{value}'" + f"Icon string too long ({len(value)} chars, max {ICON_MAX_LENGTH}): '{value}'" ) return _register_string(value, _get_pool().icons, _MAX_ICONS, "icon") From 5373412f6028b9c6dcd9a81fe187aa175909af83 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 12:03:51 -1000 Subject: [PATCH 02/42] move DEVICE_CLASS_MAX_LENGTH to esphome/core/config.py alongside other max length constants --- esphome/config_validation.py | 5 ----- esphome/core/config.py | 4 ++++ esphome/core/entity_helpers.py | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index df03f245ef5..1eac53e9b20 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -398,11 +398,6 @@ def string_strict(value): ) -# Max device class string length (47 chars + null = 48-byte PROGMEM buffer) -# Keep in sync with MAX_DEVICE_CLASS_LENGTH in esphome/core/entity_base.h -DEVICE_CLASS_MAX_LENGTH = 47 - - def icon(value): """Validate that a given config value is a valid icon.""" from esphome.core.config import ICON_MAX_LENGTH diff --git a/esphome/core/config.py b/esphome/core/config.py index cde2d280a49..21f0684e199 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -188,6 +188,10 @@ else: # Keep in sync with ESPHOME_FRIENDLY_NAME_MAX_LEN in esphome/core/entity_base.h FRIENDLY_NAME_MAX_LEN = 120 +# Max device class string length (47 chars + null = 48-byte PROGMEM buffer) +# Keep in sync with MAX_DEVICE_CLASS_LENGTH in esphome/core/entity_base.h +DEVICE_CLASS_MAX_LENGTH = 47 + # Max icon string length (63 chars + null = 64-byte PROGMEM buffer) # Keep in sync with MAX_ICON_LENGTH in esphome/core/entity_base.h ICON_MAX_LENGTH = 63 diff --git a/esphome/core/entity_helpers.py b/esphome/core/entity_helpers.py index 70c5fff0bc1..a46d2466fdf 100644 --- a/esphome/core/entity_helpers.py +++ b/esphome/core/entity_helpers.py @@ -17,7 +17,7 @@ from esphome.const import ( CONF_UNIT_OF_MEASUREMENT, ) from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority -from esphome.core.config import ICON_MAX_LENGTH +from esphome.core.config import DEVICE_CLASS_MAX_LENGTH, ICON_MAX_LENGTH from esphome.cpp_generator import MockObj, RawStatement, add, get_variable import esphome.final_validate as fv from esphome.helpers import cpp_string_escape, fnv1_hash_object_id, sanitize, snake_case @@ -179,9 +179,9 @@ def _register_string( def register_device_class(value: str) -> int: """Register a device_class string and return its 1-based index.""" - if value and len(value) > cv.DEVICE_CLASS_MAX_LENGTH: + if value and len(value) > DEVICE_CLASS_MAX_LENGTH: raise ValueError( - f"Device class string too long ({len(value)} chars, max {cv.DEVICE_CLASS_MAX_LENGTH}): '{value}'" + f"Device class string too long ({len(value)} chars, max {DEVICE_CLASS_MAX_LENGTH}): '{value}'" ) return _register_string( value, _get_pool().device_classes, _MAX_DEVICE_CLASSES, "device_class" From 8911d9d28f1adb2414f67a00c0035295e554f388 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Tue, 3 Mar 2026 19:42:36 -0600 Subject: [PATCH 03/42] [media_source] Clarify threading contract (#14433) --- esphome/components/media_source/media_source.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/components/media_source/media_source.h b/esphome/components/media_source/media_source.h index 688c27134f2..f21ba486b87 100644 --- a/esphome/components/media_source/media_source.h +++ b/esphome/components/media_source/media_source.h @@ -67,11 +67,13 @@ class MediaSource { /// @brief Start playing the given URI /// Sources should validate the URI and state, returning false if the source is busy. /// The orchestrator is responsible for stopping active sources before starting a new one. + /// @note Must only be called from the main loop. /// @param uri URI to play; e.g., "http://stream_url" /// @return true if playback started successfully, false otherwise virtual bool play_uri(const std::string &uri) = 0; - /// @brief Handle playback commands (pause, stop, next, etc.) + /// @brief Handle playback commands; e.g., pause, stop, next, etc. + /// @note Must only be called from the main loop. /// @param command Command to execute virtual void handle_command(MediaSourceCommand command) = 0; @@ -81,7 +83,8 @@ class MediaSource { // === State Access === - /// @brief Get current playback state (must only be called from the main loop) + /// @brief Get current playback state + /// @note Must only be called from the main loop. /// @return Current state of this source MediaSourceState get_state() const { return this->state_; } @@ -136,9 +139,10 @@ class MediaSource { virtual void notify_audio_played(uint32_t frames, int64_t timestamp) {} protected: - /// @brief Update state and notify listener (must only be called from the main loop) + /// @brief Update state and notify listener /// This is the only way to change state_, ensuring listener notifications always fire. /// Sources running FreeRTOS tasks should signal via event groups and call this from loop(). + /// @note Must only be called from the main loop. /// @param state New state to set void set_state_(MediaSourceState state) { if (this->state_ != state) { From cba34e770e8077f95305bdbbf5352def17d58dcf Mon Sep 17 00:00:00 2001 From: Tilman Vogel Date: Wed, 4 Mar 2026 03:18:36 +0100 Subject: [PATCH 04/42] [core] improve help text for --device option, mention `OTA` (#14445) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 7 ++++--- esphome/const.py | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index ffedb90bde4..0164e2eeb33 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -23,6 +23,7 @@ import esphome.codegen as cg from esphome.config import iter_component_configs, read_config, strip_default_ids from esphome.const import ( ALLOWED_NAME_CHARS, + ARGUMENT_HELP_DEVICE, CONF_API, CONF_BAUD_RATE, CONF_BROKER, @@ -1367,7 +1368,7 @@ def parse_args(argv): parser_upload.add_argument( "--device", action="append", - help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.", + help=ARGUMENT_HELP_DEVICE, ) parser_upload.add_argument( "--upload_speed", @@ -1390,7 +1391,7 @@ def parse_args(argv): parser_logs.add_argument( "--device", action="append", - help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.", + help=ARGUMENT_HELP_DEVICE, ) parser_logs.add_argument( "--reset", @@ -1420,7 +1421,7 @@ def parse_args(argv): parser_run.add_argument( "--device", action="append", - help="Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses.", + help=ARGUMENT_HELP_DEVICE, ) parser_run.add_argument( "--upload_speed", diff --git a/esphome/const.py b/esphome/const.py index d5625f6a549..060e9625739 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -11,6 +11,9 @@ VALID_SUBSTITUTIONS_CHARACTERS = ( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" ) +# CLI Help Text Constants +ARGUMENT_HELP_DEVICE = "Manually specify the serial port/address to use, for example /dev/ttyUSB0. Can be specified multiple times for fallback addresses. Use 'OTA' for resolving from MQTT, DNS or mDNS and avoiding the interactive prompt." + class Platform(StrEnum): """Platform identifiers for ESPHome.""" From b0279752ebc64e599005beed129e7b8aeb54d888 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 17:09:36 -1000 Subject: [PATCH 05/42] tweak --- esphome/components/api/api_connection.cpp | 246 +++++------- esphome/components/api/api_connection.h | 86 ++++- esphome/components/api/api_pb2.h | 361 +++++++++--------- esphome/components/api/api_pb2_service.h | 8 - esphome/components/api/api_server.cpp | 6 +- esphome/components/api/list_entities.cpp | 2 +- esphome/components/api/proto.h | 38 +- .../bluetooth_proxy/bluetooth_connection.cpp | 12 +- .../bluetooth_proxy/bluetooth_proxy.cpp | 18 +- .../voice_assistant/voice_assistant.cpp | 11 +- .../components/zwave_proxy/zwave_proxy.cpp | 6 +- script/api_protobuf/api_protobuf.py | 14 +- 12 files changed, 389 insertions(+), 419 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 5f0cc107553..7a9518687bf 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -274,7 +274,7 @@ void APIConnection::check_keepalive_(uint32_t now) { // Only send ping if we're not disconnecting ESP_LOGVV(TAG, "Sending keepalive PING"); PingRequest req; - this->flags_.sent_ping = this->send_message(req, PingRequest::MESSAGE_TYPE); + this->flags_.sent_ping = this->send_message(req); if (!this->flags_.sent_ping) { // If we can't send the ping request directly (tx_buffer full), // schedule it at the front of the batch so it will be sent with priority @@ -335,7 +335,7 @@ bool APIConnection::send_disconnect_response_() { this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("disconnected")); this->flags_.next_close = true; DisconnectResponse resp; - return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE); + return this->send_message(resp); } void APIConnection::on_disconnect_response() { // Don't close socket here, let APIServer::loop() do it @@ -343,70 +343,21 @@ void APIConnection::on_disconnect_response() { this->flags_.remove = true; } -// Encodes a message to the buffer and returns the total number of bytes used, -// including header and footer overhead. Returns 0 if the message doesn't fit. -uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint8_t message_type, APIConnection *conn, - uint32_t remaining_size) { -#ifdef HAS_PROTO_MESSAGE_DUMP - // If in log-only mode, just log and return - if (conn->flags_.log_only_mode) { - DumpBuffer dump_buf; - conn->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); - return 1; // Return non-zero to indicate "success" for logging - } +// 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 #endif - - // Calculate size - uint32_t calculated_size = msg.calculated_size(); - - // Cache frame sizes to avoid repeated virtual calls - const uint8_t header_padding = conn->helper_->frame_header_padding(); - const uint8_t footer_size = conn->helper_->frame_footer_size(); - - // Calculate total size with padding for buffer allocation - size_t total_calculated_size = calculated_size + header_padding + footer_size; - - // Check if it fits - if (total_calculated_size > remaining_size) { - return 0; // Doesn't fit - } - - // Get buffer size after allocation (which includes header padding) - std::vector &shared_buf = conn->parent_->get_shared_buffer_ref(); - - if (conn->flags_.batch_first_message) { - // First message - buffer already prepared by caller, just clear flag - conn->flags_.batch_first_message = false; - } else { - // Batch message second or later - // Add padding for previous message footer + this message header - size_t current_size = shared_buf.size(); - shared_buf.reserve(current_size + total_calculated_size); - shared_buf.resize(current_size + footer_size + header_padding); - } - - // Pre-resize buffer to include payload, then encode through raw pointer - size_t write_start = shared_buf.size(); - shared_buf.resize(write_start + calculated_size); - ProtoWriteBuffer buffer{&shared_buf, write_start}; - msg.encode(buffer); - - // Return total size (header + payload + footer) - return static_cast(header_padding + calculated_size + footer_size); -} - -uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg, - uint8_t message_type, APIConnection *conn, - uint32_t remaining_size) { - // Set common fields that are shared by all entity types +) { 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 - // Buffer must remain in scope until encode_message_to_buffer is called - 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); } @@ -415,9 +366,7 @@ uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResp msg.name = entity->get_name(); } - // Set common EntityBase properties #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(); @@ -425,16 +374,6 @@ uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResp #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - return encode_message_to_buffer(msg, message_type, conn, remaining_size); -} - -uint16_t APIConnection::fill_and_encode_entity_info_with_device_class(EntityBase *entity, InfoResponseProtoMessage &msg, - StringRef &device_class_field, - uint8_t message_type, 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, message_type, conn, remaining_size); } #ifdef USE_BINARY_SENSOR @@ -448,16 +387,14 @@ uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConn BinarySensorStateResponse resp; resp.state = binary_sensor->state; resp.missing_state = !binary_sensor->has_state(); - return fill_and_encode_entity_state(binary_sensor, resp, BinarySensorStateResponse::MESSAGE_TYPE, conn, - remaining_size); + return fill_and_encode_entity_state(binary_sensor, resp, conn, remaining_size); } uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *binary_sensor = static_cast(entity); ListEntitiesBinarySensorResponse msg; msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); - return fill_and_encode_entity_info_with_device_class( - binary_sensor, msg, msg.device_class, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(binary_sensor, msg, msg.device_class, conn, remaining_size); } #endif @@ -473,7 +410,7 @@ uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection * if (traits.get_supports_tilt()) msg.tilt = cover->tilt; msg.current_operation = static_cast(cover->current_operation); - return fill_and_encode_entity_state(cover, msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(cover, msg, conn, remaining_size); } uint16_t APIConnection::try_send_cover_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *cover = static_cast(entity); @@ -483,8 +420,7 @@ uint16_t APIConnection::try_send_cover_info(EntityBase *entity, APIConnection *c msg.supports_position = traits.get_supports_position(); msg.supports_tilt = traits.get_supports_tilt(); msg.supports_stop = traits.get_supports_stop(); - return fill_and_encode_entity_info_with_device_class(cover, msg, msg.device_class, - ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(cover, msg, msg.device_class, conn, remaining_size); } void APIConnection::on_cover_command_request(const CoverCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(cover::Cover, cover, cover) @@ -516,7 +452,7 @@ uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *co msg.direction = static_cast(fan->direction); if (traits.supports_preset_modes() && fan->has_preset_mode()) msg.preset_mode = fan->get_preset_mode(); - return fill_and_encode_entity_state(fan, msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(fan, msg, conn, remaining_size); } uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *fan = static_cast(entity); @@ -527,7 +463,7 @@ uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *con msg.supports_direction = traits.supports_direction(); msg.supported_speed_count = traits.supported_speed_count(); msg.supported_preset_modes = &traits.supported_preset_modes(); - return fill_and_encode_entity_info(fan, msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(fan, msg, conn, remaining_size); } void APIConnection::on_fan_command_request(const FanCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(fan::Fan, fan, fan) @@ -570,7 +506,7 @@ uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection * if (light->supports_effects()) { resp.effect = light->get_effect_name(); } - return fill_and_encode_entity_state(light, resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(light, resp, conn, remaining_size); } uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *light = static_cast(entity); @@ -595,7 +531,7 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c } } msg.effects = &effects_list; - return fill_and_encode_entity_info(light, msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(light, msg, conn, remaining_size); } void APIConnection::on_light_command_request(const LightCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(light::LightState, light, light) @@ -640,7 +576,7 @@ uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection SensorStateResponse resp; resp.state = sensor->state; resp.missing_state = !sensor->has_state(); - return fill_and_encode_entity_state(sensor, resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(sensor, resp, conn, remaining_size); } uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { @@ -650,8 +586,7 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection * msg.accuracy_decimals = sensor->get_accuracy_decimals(); msg.force_update = sensor->get_force_update(); msg.state_class = static_cast(sensor->get_state_class()); - return fill_and_encode_entity_info_with_device_class(sensor, msg, msg.device_class, - ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(sensor, msg, msg.device_class, conn, remaining_size); } #endif @@ -664,15 +599,14 @@ uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection auto *a_switch = static_cast(entity); SwitchStateResponse resp; resp.state = a_switch->state; - return fill_and_encode_entity_state(a_switch, resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(a_switch, resp, conn, remaining_size); } uint16_t APIConnection::try_send_switch_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *a_switch = static_cast(entity); ListEntitiesSwitchResponse msg; msg.assumed_state = a_switch->assumed_state(); - return fill_and_encode_entity_info_with_device_class(a_switch, msg, msg.device_class, - ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(a_switch, msg, msg.device_class, conn, remaining_size); } void APIConnection::on_switch_command_request(const SwitchCommandRequest &msg) { ENTITY_COMMAND_GET(switch_::Switch, a_switch, switch) @@ -696,13 +630,12 @@ uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnec TextSensorStateResponse resp; resp.state = StringRef(text_sensor->state); resp.missing_state = !text_sensor->has_state(); - return fill_and_encode_entity_state(text_sensor, resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(text_sensor, resp, conn, remaining_size); } uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *text_sensor = static_cast(entity); ListEntitiesTextSensorResponse msg; - return fill_and_encode_entity_info_with_device_class( - text_sensor, msg, msg.device_class, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(text_sensor, msg, msg.device_class, conn, remaining_size); } #endif @@ -742,7 +675,7 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection resp.current_humidity = climate->current_humidity; if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY)) resp.target_humidity = climate->target_humidity; - return fill_and_encode_entity_state(climate, resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(climate, resp, conn, remaining_size); } uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *climate = static_cast(entity); @@ -769,7 +702,7 @@ uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection msg.supported_presets = &traits.get_supported_presets(); msg.supported_custom_presets = &traits.get_supported_custom_presets(); msg.supported_swing_modes = &traits.get_supported_swing_modes(); - return fill_and_encode_entity_info(climate, msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(climate, msg, conn, remaining_size); } void APIConnection::on_climate_command_request(const ClimateCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(climate::Climate, climate, climate) @@ -807,7 +740,7 @@ uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection NumberStateResponse resp; resp.state = number->state; resp.missing_state = !number->has_state(); - return fill_and_encode_entity_state(number, resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(number, resp, conn, remaining_size); } uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { @@ -818,8 +751,7 @@ uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection * msg.min_value = number->traits.get_min_value(); msg.max_value = number->traits.get_max_value(); msg.step = number->traits.get_step(); - return fill_and_encode_entity_info_with_device_class(number, msg, msg.device_class, - ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(number, msg, msg.device_class, conn, remaining_size); } void APIConnection::on_number_command_request(const NumberCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(number::Number, number, number) @@ -839,12 +771,12 @@ uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *c resp.year = date->year; resp.month = date->month; resp.day = date->day; - return fill_and_encode_entity_state(date, resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(date, resp, conn, remaining_size); } uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *date = static_cast(entity); ListEntitiesDateResponse msg; - return fill_and_encode_entity_info(date, msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(date, msg, conn, remaining_size); } void APIConnection::on_date_command_request(const DateCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(datetime::DateEntity, date, date) @@ -864,12 +796,12 @@ uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *c resp.hour = time->hour; resp.minute = time->minute; resp.second = time->second; - return fill_and_encode_entity_state(time, resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(time, resp, conn, remaining_size); } uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *time = static_cast(entity); ListEntitiesTimeResponse msg; - return fill_and_encode_entity_info(time, msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(time, msg, conn, remaining_size); } void APIConnection::on_time_command_request(const TimeCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(datetime::TimeEntity, time, time) @@ -891,12 +823,12 @@ uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnectio ESPTime state = datetime->state_as_esptime(); resp.epoch_seconds = state.timestamp; } - return fill_and_encode_entity_state(datetime, resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(datetime, resp, conn, remaining_size); } uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *datetime = static_cast(entity); ListEntitiesDateTimeResponse msg; - return fill_and_encode_entity_info(datetime, msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(datetime, msg, conn, remaining_size); } void APIConnection::on_date_time_command_request(const DateTimeCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(datetime::DateTimeEntity, datetime, datetime) @@ -915,7 +847,7 @@ uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *c TextStateResponse resp; resp.state = StringRef(text->state); resp.missing_state = !text->has_state(); - return fill_and_encode_entity_state(text, resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(text, resp, conn, remaining_size); } uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { @@ -925,7 +857,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co msg.min_length = text->traits.get_min_length(); msg.max_length = text->traits.get_max_length(); msg.pattern = text->traits.get_pattern_ref(); - return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(text, msg, conn, remaining_size); } void APIConnection::on_text_command_request(const TextCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(text::Text, text, text) @@ -944,14 +876,14 @@ uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection SelectStateResponse resp; resp.state = select->current_option(); resp.missing_state = !select->has_state(); - return fill_and_encode_entity_state(select, resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(select, resp, conn, remaining_size); } uint16_t APIConnection::try_send_select_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *select = static_cast(entity); ListEntitiesSelectResponse msg; msg.options = &select->traits.get_options(); - return fill_and_encode_entity_info(select, msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(select, msg, conn, remaining_size); } void APIConnection::on_select_command_request(const SelectCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(select::Select, select, select) @@ -964,8 +896,7 @@ void APIConnection::on_select_command_request(const SelectCommandRequest &msg) { uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *button = static_cast(entity); ListEntitiesButtonResponse msg; - return fill_and_encode_entity_info_with_device_class(button, msg, msg.device_class, - ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(button, msg, msg.device_class, conn, remaining_size); } void esphome::api::APIConnection::on_button_command_request(const ButtonCommandRequest &msg) { ENTITY_COMMAND_GET(button::Button, button, button) @@ -982,7 +913,7 @@ uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *c auto *a_lock = static_cast(entity); LockStateResponse resp; resp.state = static_cast(a_lock->state); - return fill_and_encode_entity_state(a_lock, resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(a_lock, resp, conn, remaining_size); } uint16_t APIConnection::try_send_lock_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { @@ -991,7 +922,7 @@ uint16_t APIConnection::try_send_lock_info(EntityBase *entity, APIConnection *co msg.assumed_state = a_lock->traits.get_assumed_state(); msg.supports_open = a_lock->traits.get_supports_open(); msg.requires_code = a_lock->traits.get_requires_code(); - return fill_and_encode_entity_info(a_lock, msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(a_lock, msg, conn, remaining_size); } void APIConnection::on_lock_command_request(const LockCommandRequest &msg) { ENTITY_COMMAND_GET(lock::Lock, a_lock, lock) @@ -1019,7 +950,7 @@ uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection * ValveStateResponse resp; resp.position = valve->position; resp.current_operation = static_cast(valve->current_operation); - return fill_and_encode_entity_state(valve, resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(valve, resp, conn, remaining_size); } uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *valve = static_cast(entity); @@ -1028,8 +959,7 @@ uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *c msg.assumed_state = traits.get_is_assumed_state(); msg.supports_position = traits.get_supports_position(); msg.supports_stop = traits.get_supports_stop(); - return fill_and_encode_entity_info_with_device_class(valve, msg, msg.device_class, - ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(valve, msg, msg.device_class, conn, remaining_size); } void APIConnection::on_valve_command_request(const ValveCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(valve::Valve, valve, valve) @@ -1055,7 +985,7 @@ uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConne resp.state = static_cast(report_state); resp.volume = media_player->volume; resp.muted = media_player->is_muted(); - return fill_and_encode_entity_state(media_player, resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(media_player, resp, conn, remaining_size); } uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *media_player = static_cast(entity); @@ -1072,8 +1002,7 @@ uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnec media_format.purpose = static_cast(supported_format.purpose); media_format.sample_bytes = supported_format.sample_bytes; } - return fill_and_encode_entity_info(media_player, msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn, - remaining_size); + return fill_and_encode_entity_info(media_player, msg, conn, remaining_size); } void APIConnection::on_media_player_command_request(const MediaPlayerCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(media_player::MediaPlayer, media_player, media_player) @@ -1114,7 +1043,7 @@ void APIConnection::try_send_camera_image_() { msg.device_id = camera::Camera::instance()->get_device_id(); #endif - if (!this->send_message_impl(msg, CameraImageResponse::MESSAGE_TYPE)) { + if (!this->send_message(msg)) { return; // Send failed, try again later } this->image_reader_->consume_data(to_send); @@ -1140,7 +1069,7 @@ void APIConnection::set_camera_state(std::shared_ptr image) uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *camera = static_cast(entity); ListEntitiesCameraResponse msg; - return fill_and_encode_entity_info(camera, msg, ListEntitiesCameraResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(camera, msg, conn, remaining_size); } void APIConnection::on_camera_image_request(const CameraImageRequest &msg) { if (camera::Camera::instance() == nullptr) @@ -1295,7 +1224,7 @@ void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnno bool APIConnection::send_voice_assistant_get_configuration_response_(const VoiceAssistantConfigurationRequest &msg) { VoiceAssistantConfigurationResponse resp; if (!this->check_voice_assistant_api_connection_()) { - return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE); + return this->send_message(resp); } auto &config = voice_assistant::global_voice_assistant->get_configuration(); @@ -1327,7 +1256,7 @@ bool APIConnection::send_voice_assistant_get_configuration_response_(const Voice resp.active_wake_words = &config.active_wake_words; resp.max_active_wake_words = config.max_active_wake_words; - return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE); + return this->send_message(resp); } void APIConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { if (!this->send_voice_assistant_get_configuration_response_(msg)) { @@ -1362,8 +1291,7 @@ uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, A auto *a_alarm_control_panel = static_cast(entity); AlarmControlPanelStateResponse resp; resp.state = static_cast(a_alarm_control_panel->get_state()); - return fill_and_encode_entity_state(a_alarm_control_panel, resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, - remaining_size); + return fill_and_encode_entity_state(a_alarm_control_panel, resp, conn, remaining_size); } uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { @@ -1372,8 +1300,7 @@ uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, AP msg.supported_features = a_alarm_control_panel->get_supported_features(); msg.requires_code = a_alarm_control_panel->get_requires_code(); msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm(); - return fill_and_encode_entity_info(a_alarm_control_panel, msg, ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE, - conn, remaining_size); + return fill_and_encode_entity_info(a_alarm_control_panel, msg, conn, remaining_size); } void APIConnection::on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) { ENTITY_COMMAND_MAKE_CALL(alarm_control_panel::AlarmControlPanel, a_alarm_control_panel, alarm_control_panel) @@ -1420,7 +1347,7 @@ uint16_t APIConnection::try_send_water_heater_state(EntityBase *entity, APIConne resp.target_temperature_high = wh->get_target_temperature_high(); resp.state = wh->get_state(); - return fill_and_encode_entity_state(wh, resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(wh, resp, conn, remaining_size); } uint16_t APIConnection::try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *wh = static_cast(entity); @@ -1431,7 +1358,7 @@ uint16_t APIConnection::try_send_water_heater_info(EntityBase *entity, APIConnec msg.target_temperature_step = traits.get_target_temperature_step(); msg.supported_modes = &traits.get_supported_modes(); msg.supported_features = traits.get_feature_flags(); - return fill_and_encode_entity_info(wh, msg, ListEntitiesWaterHeaterResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(wh, msg, conn, remaining_size); } void APIConnection::on_water_heater_command_request(const WaterHeaterCommandRequest &msg) { @@ -1467,15 +1394,14 @@ uint16_t APIConnection::try_send_event_response(event::Event *event, StringRef e uint32_t remaining_size) { EventResponse resp; resp.event_type = event_type; - return fill_and_encode_entity_state(event, resp, EventResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(event, resp, conn, remaining_size); } uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *event = static_cast(entity); ListEntitiesEventResponse msg; msg.event_types = &event->get_event_types(); - return fill_and_encode_entity_info_with_device_class(event, msg, msg.device_class, - ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(event, msg, msg.device_class, conn, remaining_size); } #endif @@ -1492,9 +1418,7 @@ void APIConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRF #endif } -void APIConnection::send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg) { - this->send_message(msg, InfraredRFReceiveEvent::MESSAGE_TYPE); -} +void APIConnection::send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg) { this->send_message(msg); } #endif #ifdef USE_INFRARED @@ -1502,7 +1426,7 @@ uint16_t APIConnection::try_send_infrared_info(EntityBase *entity, APIConnection auto *infrared = static_cast(entity); ListEntitiesInfraredResponse msg; msg.capabilities = infrared->get_capability_flags(); - return fill_and_encode_entity_info(infrared, msg, ListEntitiesInfraredResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info(infrared, msg, conn, remaining_size); } #endif @@ -1526,13 +1450,12 @@ uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection resp.release_summary = StringRef(update->update_info.summary); resp.release_url = StringRef(update->update_info.release_url); } - return fill_and_encode_entity_state(update, resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_state(update, resp, conn, remaining_size); } uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { auto *update = static_cast(entity); ListEntitiesUpdateResponse msg; - return fill_and_encode_entity_info_with_device_class(update, msg, msg.device_class, - ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(update, msg, msg.device_class, conn, remaining_size); } void APIConnection::on_update_command_request(const UpdateCommandRequest &msg) { ENTITY_COMMAND_GET(update::UpdateEntity, update, update) @@ -1558,7 +1481,7 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char SubscribeLogsResponse msg; msg.level = static_cast(level); msg.set_message(reinterpret_cast(line), message_len); - return this->send_message_impl(msg, SubscribeLogsResponse::MESSAGE_TYPE); + return this->send_message(msg); } void APIConnection::complete_authentication_() { @@ -1615,12 +1538,12 @@ bool APIConnection::send_hello_response_(const HelloRequest &msg) { // Auto-authenticate - password auth was removed in ESPHome 2026.1.0 this->complete_authentication_(); - return this->send_message(resp, HelloResponse::MESSAGE_TYPE); + return this->send_message(resp); } bool APIConnection::send_ping_response_() { PingResponse resp; - return this->send_message(resp, PingResponse::MESSAGE_TYPE); + return this->send_message(resp); } bool APIConnection::send_device_info_response_() { @@ -1744,7 +1667,7 @@ bool APIConnection::send_device_info_response_() { } #endif - return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE); + return this->send_message(resp); } void APIConnection::on_hello_request(const HelloRequest &msg) { if (!this->send_hello_response_(msg)) { @@ -1844,7 +1767,7 @@ void APIConnection::send_execute_service_response(uint32_t call_id, bool success resp.call_id = call_id; resp.success = success; resp.error_message = error_message; - this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE); + this->send_message(resp); } #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON void APIConnection::send_execute_service_response(uint32_t call_id, bool success, StringRef error_message, @@ -1855,7 +1778,7 @@ void APIConnection::send_execute_service_response(uint32_t call_id, bool success resp.error_message = error_message; resp.response_data = response_data; resp.response_data_len = response_data_len; - this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE); + this->send_message(resp); } #endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #endif // USE_API_USER_DEFINED_ACTION_RESPONSES @@ -1894,7 +1817,7 @@ bool APIConnection::send_noise_encryption_set_key_response_(const NoiseEncryptio resp.success = true; } - return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE); + return this->send_message(resp); } void APIConnection::on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) { if (!this->send_noise_encryption_set_key_response_(msg)) { @@ -1923,16 +1846,37 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { } return false; } -bool APIConnection::send_message_impl(const ProtoMessage &msg, uint8_t message_type) { - uint32_t payload_size = msg.calculated_size(); - std::vector &shared_buf = this->parent_->get_shared_buffer_ref(); +bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, + const void *msg) { + auto &shared_buf = this->parent_->get_shared_buffer_ref(); this->prepare_first_message_buffer(shared_buf, payload_size); size_t write_start = shared_buf.size(); shared_buf.resize(write_start + payload_size); ProtoWriteBuffer buffer{&shared_buf, write_start}; - msg.encode(buffer); + encode_fn(msg, buffer); return this->send_buffer(ProtoWriteBuffer{&shared_buf}, message_type); } +uint16_t APIConnection::encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, + APIConnection *conn, uint32_t remaining_size) { + const uint8_t header_padding = conn->helper_->frame_header_padding(); + const uint8_t footer_size = conn->helper_->frame_footer_size(); + size_t total_calculated_size = calculated_size + header_padding + footer_size; + if (total_calculated_size > remaining_size) + return 0; + std::vector &shared_buf = conn->parent_->get_shared_buffer_ref(); + if (conn->flags_.batch_first_message) { + conn->flags_.batch_first_message = false; + } else { + size_t current_size = shared_buf.size(); + shared_buf.reserve(current_size + total_calculated_size); + shared_buf.resize(current_size + footer_size + header_padding); + } + size_t write_start = shared_buf.size(); + shared_buf.resize(write_start + calculated_size); + ProtoWriteBuffer buffer{&shared_buf, write_start}; + encode_fn(msg, buffer); + return static_cast(header_padding + calculated_size + footer_size); +} bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) { const bool is_log_message = (message_type == SubscribeLogsResponse::MESSAGE_TYPE); @@ -2291,17 +2235,17 @@ uint16_t APIConnection::dispatch_message_(const DeferredBatch::BatchItem &item, uint16_t APIConnection::try_send_list_info_done(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { ListEntitiesDoneResponse resp; - return encode_message_to_buffer(resp, ListEntitiesDoneResponse::MESSAGE_TYPE, conn, remaining_size); + return encode_message_to_buffer(resp, conn, remaining_size); } uint16_t APIConnection::try_send_disconnect_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { DisconnectRequest req; - return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size); + return encode_message_to_buffer(req, conn, remaining_size); } uint16_t APIConnection::try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size) { PingRequest req; - return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size); + return encode_message_to_buffer(req, conn, remaining_size); } #ifdef USE_API_HOMEASSISTANT_STATES @@ -2320,7 +2264,7 @@ void APIConnection::process_state_subscriptions_() { resp.attribute = it.attribute != nullptr ? StringRef(it.attribute) : StringRef(""); resp.once = it.once; - if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) { + if (this->send_message(resp)) { this->state_subs_at_++; } } diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 83ec20481d2..21948ba2470 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -123,7 +123,7 @@ class APIConnection final : public APIServerConnectionBase { void send_homeassistant_action(const HomeassistantActionRequest &call) { if (!this->flags_.service_call_subscription) return; - this->send_message(call, HomeassistantActionRequest::MESSAGE_TYPE); + this->send_message(call); } #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES void on_homeassistant_action_response(const HomeassistantActionResponse &msg) override; @@ -147,7 +147,7 @@ class APIConnection final : public APIServerConnectionBase { #ifdef USE_HOMEASSISTANT_TIME void send_time_request() { GetTimeRequest req; - this->send_message(req, GetTimeRequest::MESSAGE_TYPE); + this->send_message(req); } #endif @@ -257,7 +257,17 @@ class APIConnection final : public APIServerConnectionBase { void on_fatal_error() override; void on_no_setup_connection() override; - bool send_message_impl(const ProtoMessage &msg, uint8_t message_type) override; + + // Function pointer type for type-erased message encoding + using MessageEncodeFn = void (*)(const void *, ProtoWriteBuffer &); + + template bool send_message(const T &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + DumpBuffer dump_buf; + this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); +#endif + return this->send_message_(calculated_size_of(msg), T::MESSAGE_TYPE, &encode_msg_, &msg); + } void prepare_first_message_buffer(std::vector &shared_buf, size_t header_padding, size_t total_size) { shared_buf.clear(); @@ -312,28 +322,74 @@ class APIConnection final : public APIServerConnectionBase { void process_state_subscriptions_(); #endif - // Non-template helper to encode any ProtoMessage - static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint8_t message_type, APIConnection *conn, - uint32_t remaining_size); + // Encode thunk — converts void* back to concrete type for direct encode() call + template static void encode_msg_(const void *msg, ProtoWriteBuffer &buffer) { + static_cast(msg)->encode(buffer); + } + + // Non-template buffer management for send_message + bool send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg); + + // Non-template buffer management for batch encoding + static uint16_t encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, + APIConnection *conn, uint32_t remaining_size); + + // Thin template wrapper — computes size, delegates buffer work to non-template helper + template static uint16_t encode_message_to_buffer(T &msg, APIConnection *conn, uint32_t remaining_size) { +#ifdef HAS_PROTO_MESSAGE_DUMP + if (conn->flags_.log_only_mode) { + DumpBuffer dump_buf; + conn->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); + return 1; + } +#endif + return encode_to_buffer_(calculated_size_of(msg), &encode_msg_, &msg, conn, remaining_size); + } // Helper to fill entity state base and encode message - static uint16_t fill_and_encode_entity_state(EntityBase *entity, StateResponseProtoMessage &msg, uint8_t message_type, - APIConnection *conn, uint32_t remaining_size) { + 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, message_type, conn, remaining_size); + return encode_message_to_buffer(msg, conn, remaining_size); } - // Helper to fill entity info base and encode message - static uint16_t fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg, uint8_t message_type, - APIConnection *conn, uint32_t 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 + ); + + // Template to fill entity info and encode + 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); + } // Wrapper for entity types that have a device_class field - static uint16_t fill_and_encode_entity_info_with_device_class(EntityBase *entity, InfoResponseProtoMessage &msg, - StringRef &device_class_field, uint8_t message_type, - APIConnection *conn, uint32_t remaining_size); + 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); + } #ifdef USE_VOICE_ASSISTANT // Helper to check voice assistant validity and connection ownership diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index a97f6c0a762..84f9baa5a56 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -333,9 +333,6 @@ class InfoResponseProtoMessage : public ProtoMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif - - protected: - ~InfoResponseProtoMessage() = default; }; class StateResponseProtoMessage : public ProtoMessage { @@ -344,9 +341,6 @@ class StateResponseProtoMessage : public ProtoMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif - - protected: - ~StateResponseProtoMessage() = default; }; class CommandProtoMessage : public ProtoDecodableMessage { @@ -355,9 +349,6 @@ class CommandProtoMessage : public ProtoDecodableMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif - - protected: - ~CommandProtoMessage() = default; }; class HelloRequest final : public ProtoDecodableMessage { public: @@ -388,8 +379,8 @@ class HelloResponse final : public ProtoMessage { uint32_t api_version_minor{0}; StringRef server_info{}; StringRef name{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -453,8 +444,8 @@ class AreaInfo final : public ProtoMessage { public: uint32_t area_id{0}; StringRef name{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -468,8 +459,8 @@ class DeviceInfo final : public ProtoMessage { uint32_t device_id{0}; StringRef name{}; uint32_t area_id{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -533,8 +524,8 @@ class DeviceInfoResponse final : public ProtoMessage { #ifdef USE_ZWAVE_PROXY uint32_t zwave_home_id{0}; #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -564,8 +555,8 @@ class ListEntitiesBinarySensorResponse final : public InfoResponseProtoMessage { #endif StringRef device_class{}; bool is_status_binary_sensor{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -581,8 +572,8 @@ class BinarySensorStateResponse final : public StateResponseProtoMessage { #endif bool state{false}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -603,8 +594,8 @@ class ListEntitiesCoverResponse final : public InfoResponseProtoMessage { bool supports_tilt{false}; StringRef device_class{}; bool supports_stop{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -621,8 +612,8 @@ class CoverStateResponse final : public StateResponseProtoMessage { float position{0.0f}; float tilt{0.0f}; enums::CoverOperation current_operation{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -663,8 +654,8 @@ class ListEntitiesFanResponse final : public InfoResponseProtoMessage { bool supports_direction{false}; int32_t supported_speed_count{0}; const std::vector *supported_preset_modes{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -683,8 +674,8 @@ class FanStateResponse final : public StateResponseProtoMessage { enums::FanDirection direction{}; int32_t speed_level{0}; StringRef preset_mode{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -730,8 +721,8 @@ class ListEntitiesLightResponse final : public InfoResponseProtoMessage { float min_mireds{0.0f}; float max_mireds{0.0f}; const FixedVector *effects{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -757,8 +748,8 @@ class LightStateResponse final : public StateResponseProtoMessage { float cold_white{0.0f}; float warm_white{0.0f}; StringRef effect{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -821,8 +812,8 @@ class ListEntitiesSensorResponse final : public InfoResponseProtoMessage { bool force_update{false}; StringRef device_class{}; enums::SensorStateClass state_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -838,8 +829,8 @@ class SensorStateResponse final : public StateResponseProtoMessage { #endif float state{0.0f}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -857,8 +848,8 @@ class ListEntitiesSwitchResponse final : public InfoResponseProtoMessage { #endif bool assumed_state{false}; StringRef device_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -873,8 +864,8 @@ class SwitchStateResponse final : public StateResponseProtoMessage { const char *message_name() const override { return "switch_state_response"; } #endif bool state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -907,8 +898,8 @@ class ListEntitiesTextSensorResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_text_sensor_response"; } #endif StringRef device_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -924,8 +915,8 @@ class TextSensorStateResponse final : public StateResponseProtoMessage { #endif StringRef state{}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -963,8 +954,8 @@ class SubscribeLogsResponse final : public ProtoMessage { this->message_ptr_ = data; this->message_len_ = len; } - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -996,8 +987,8 @@ class NoiseEncryptionSetKeyResponse final : public ProtoMessage { const char *message_name() const override { return "noise_encryption_set_key_response"; } #endif bool success{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1010,8 +1001,8 @@ class HomeassistantServiceMap final : public ProtoMessage { public: StringRef key{}; StringRef value{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1039,8 +1030,8 @@ class HomeassistantActionRequest final : public ProtoMessage { #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON StringRef response_template{}; #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1083,8 +1074,8 @@ class SubscribeHomeAssistantStateResponse final : public ProtoMessage { StringRef entity_id{}; StringRef attribute{}; bool once{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1174,8 +1165,8 @@ class ListEntitiesServicesArgument final : public ProtoMessage { public: StringRef name{}; enums::ServiceArgType type{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1193,8 +1184,8 @@ class ListEntitiesServicesResponse final : public ProtoMessage { uint32_t key{0}; FixedVector args{}; enums::SupportsResponseType supports_response{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1263,8 +1254,8 @@ class ExecuteServiceResponse final : public ProtoMessage { const uint8_t *response_data{nullptr}; uint16_t response_data_len{0}; #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1280,8 +1271,8 @@ class ListEntitiesCameraResponse final : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_camera_response"; } #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1302,8 +1293,8 @@ class CameraImageResponse final : public StateResponseProtoMessage { this->data_len_ = len; } bool done{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1353,8 +1344,8 @@ class ListEntitiesClimateResponse final : public InfoResponseProtoMessage { float visual_min_humidity{0.0f}; float visual_max_humidity{0.0f}; uint32_t feature_flags{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1381,8 +1372,8 @@ class ClimateStateResponse final : public StateResponseProtoMessage { StringRef custom_preset{}; float current_humidity{0.0f}; float target_humidity{0.0f}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1439,8 +1430,8 @@ class ListEntitiesWaterHeaterResponse final : public InfoResponseProtoMessage { float target_temperature_step{0.0f}; const water_heater::WaterHeaterModeMask *supported_modes{}; uint32_t supported_features{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1460,8 +1451,8 @@ class WaterHeaterStateResponse final : public StateResponseProtoMessage { uint32_t state{0}; float target_temperature_low{0.0f}; float target_temperature_high{0.0f}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1504,8 +1495,8 @@ class ListEntitiesNumberResponse final : public InfoResponseProtoMessage { StringRef unit_of_measurement{}; enums::NumberMode mode{}; StringRef device_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1521,8 +1512,8 @@ class NumberStateResponse final : public StateResponseProtoMessage { #endif float state{0.0f}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1555,8 +1546,8 @@ class ListEntitiesSelectResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_select_response"; } #endif const FixedVector *options{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1572,8 +1563,8 @@ class SelectStateResponse final : public StateResponseProtoMessage { #endif StringRef state{}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1609,8 +1600,8 @@ class ListEntitiesSirenResponse final : public InfoResponseProtoMessage { const FixedVector *tones{}; bool supports_duration{false}; bool supports_volume{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1625,8 +1616,8 @@ class SirenStateResponse final : public StateResponseProtoMessage { const char *message_name() const override { return "siren_state_response"; } #endif bool state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1670,8 +1661,8 @@ class ListEntitiesLockResponse final : public InfoResponseProtoMessage { bool supports_open{false}; bool requires_code{false}; StringRef code_format{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1686,8 +1677,8 @@ class LockStateResponse final : public StateResponseProtoMessage { const char *message_name() const override { return "lock_state_response"; } #endif enums::LockState state{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1723,8 +1714,8 @@ class ListEntitiesButtonResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_button_response"; } #endif StringRef device_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1755,8 +1746,8 @@ class MediaPlayerSupportedFormat final : public ProtoMessage { uint32_t num_channels{0}; enums::MediaPlayerFormatPurpose purpose{}; uint32_t sample_bytes{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1773,8 +1764,8 @@ class ListEntitiesMediaPlayerResponse final : public InfoResponseProtoMessage { bool supports_pause{false}; std::vector supported_formats{}; uint32_t feature_flags{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1791,8 +1782,8 @@ class MediaPlayerStateResponse final : public StateResponseProtoMessage { enums::MediaPlayerState state{}; float volume{0.0f}; bool muted{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1847,8 +1838,8 @@ class BluetoothLERawAdvertisement final : public ProtoMessage { uint32_t address_type{0}; uint8_t data[62]{}; uint8_t data_len{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1864,8 +1855,8 @@ class BluetoothLERawAdvertisementsResponse final : public ProtoMessage { #endif std::array advertisements{}; uint16_t advertisements_len{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1901,8 +1892,8 @@ class BluetoothDeviceConnectionResponse final : public ProtoMessage { bool connected{false}; uint32_t mtu{0}; int32_t error{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1929,8 +1920,8 @@ class BluetoothGATTDescriptor final : public ProtoMessage { std::array uuid{}; uint32_t handle{0}; uint32_t short_uuid{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1944,8 +1935,8 @@ class BluetoothGATTCharacteristic final : public ProtoMessage { uint32_t properties{0}; FixedVector descriptors{}; uint32_t short_uuid{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1958,8 +1949,8 @@ class BluetoothGATTService final : public ProtoMessage { uint32_t handle{0}; FixedVector characteristics{}; uint32_t short_uuid{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1975,8 +1966,8 @@ class BluetoothGATTGetServicesResponse final : public ProtoMessage { #endif uint64_t address{0}; std::vector services{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1991,8 +1982,8 @@ class BluetoothGATTGetServicesDoneResponse final : public ProtoMessage { const char *message_name() const override { return "bluetooth_gatt_get_services_done_response"; } #endif uint64_t address{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2030,8 +2021,8 @@ class BluetoothGATTReadResponse final : public ProtoMessage { this->data_ptr_ = data; this->data_len_ = len; } - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2125,8 +2116,8 @@ class BluetoothGATTNotifyDataResponse final : public ProtoMessage { this->data_ptr_ = data; this->data_len_ = len; } - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2143,8 +2134,8 @@ class BluetoothConnectionsFreeResponse final : public ProtoMessage { uint32_t free{0}; uint32_t limit{0}; std::array allocated{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2161,8 +2152,8 @@ class BluetoothGATTErrorResponse final : public ProtoMessage { uint64_t address{0}; uint32_t handle{0}; int32_t error{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2178,8 +2169,8 @@ class BluetoothGATTWriteResponse final : public ProtoMessage { #endif uint64_t address{0}; uint32_t handle{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2195,8 +2186,8 @@ class BluetoothGATTNotifyResponse final : public ProtoMessage { #endif uint64_t address{0}; uint32_t handle{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2213,8 +2204,8 @@ class BluetoothDevicePairingResponse final : public ProtoMessage { uint64_t address{0}; bool paired{false}; int32_t error{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2231,8 +2222,8 @@ class BluetoothDeviceUnpairingResponse final : public ProtoMessage { uint64_t address{0}; bool success{false}; int32_t error{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2249,8 +2240,8 @@ class BluetoothDeviceClearCacheResponse final : public ProtoMessage { uint64_t address{0}; bool success{false}; int32_t error{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2267,8 +2258,8 @@ class BluetoothScannerStateResponse final : public ProtoMessage { enums::BluetoothScannerState state{}; enums::BluetoothScannerMode mode{}; enums::BluetoothScannerMode configured_mode{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2313,8 +2304,8 @@ class VoiceAssistantAudioSettings final : public ProtoMessage { uint32_t noise_suppression_level{0}; uint32_t auto_gain{0}; float volume_multiplier{0.0f}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2333,8 +2324,8 @@ class VoiceAssistantRequest final : public ProtoMessage { uint32_t flags{0}; VoiceAssistantAudioSettings audio_settings{}; StringRef wake_word_phrase{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2395,8 +2386,8 @@ class VoiceAssistantAudio final : public ProtoDecodableMessage { const uint8_t *data{nullptr}; uint16_t data_len{0}; bool end{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2453,8 +2444,8 @@ class VoiceAssistantAnnounceFinished final : public ProtoMessage { const char *message_name() const override { return "voice_assistant_announce_finished"; } #endif bool success{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2466,8 +2457,8 @@ class VoiceAssistantWakeWord final : public ProtoMessage { StringRef id{}; StringRef wake_word{}; std::vector trained_languages{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2516,8 +2507,8 @@ class VoiceAssistantConfigurationResponse final : public ProtoMessage { std::vector available_wake_words{}; const std::vector *active_wake_words{}; uint32_t max_active_wake_words{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2551,8 +2542,8 @@ class ListEntitiesAlarmControlPanelResponse final : public InfoResponseProtoMess uint32_t supported_features{0}; bool requires_code{false}; bool requires_code_to_arm{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2567,8 +2558,8 @@ class AlarmControlPanelStateResponse final : public StateResponseProtoMessage { const char *message_name() const override { return "alarm_control_panel_state_response"; } #endif enums::AlarmControlPanelState state{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2606,8 +2597,8 @@ class ListEntitiesTextResponse final : public InfoResponseProtoMessage { uint32_t max_length{0}; StringRef pattern{}; enums::TextMode mode{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2623,8 +2614,8 @@ class TextStateResponse final : public StateResponseProtoMessage { #endif StringRef state{}; bool missing_state{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2657,8 +2648,8 @@ class ListEntitiesDateResponse final : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_date_response"; } #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2676,8 +2667,8 @@ class DateStateResponse final : public StateResponseProtoMessage { uint32_t year{0}; uint32_t month{0}; uint32_t day{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2711,8 +2702,8 @@ class ListEntitiesTimeResponse final : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_time_response"; } #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2730,8 +2721,8 @@ class TimeStateResponse final : public StateResponseProtoMessage { uint32_t hour{0}; uint32_t minute{0}; uint32_t second{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2767,8 +2758,8 @@ class ListEntitiesEventResponse final : public InfoResponseProtoMessage { #endif StringRef device_class{}; const FixedVector *event_types{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2783,8 +2774,8 @@ class EventResponse final : public StateResponseProtoMessage { const char *message_name() const override { return "event_response"; } #endif StringRef event_type{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2804,8 +2795,8 @@ class ListEntitiesValveResponse final : public InfoResponseProtoMessage { bool assumed_state{false}; bool supports_position{false}; bool supports_stop{false}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2821,8 +2812,8 @@ class ValveStateResponse final : public StateResponseProtoMessage { #endif float position{0.0f}; enums::ValveOperation current_operation{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2856,8 +2847,8 @@ class ListEntitiesDateTimeResponse final : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_date_time_response"; } #endif - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2873,8 +2864,8 @@ class DateTimeStateResponse final : public StateResponseProtoMessage { #endif bool missing_state{false}; uint32_t epoch_seconds{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2907,8 +2898,8 @@ class ListEntitiesUpdateResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_update_response"; } #endif StringRef device_class{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2931,8 +2922,8 @@ class UpdateStateResponse final : public StateResponseProtoMessage { StringRef title{}; StringRef release_summary{}; StringRef release_url{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2966,8 +2957,8 @@ class ZWaveProxyFrame final : public ProtoDecodableMessage { #endif const uint8_t *data{nullptr}; uint16_t data_len{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2985,8 +2976,8 @@ class ZWaveProxyRequest final : public ProtoDecodableMessage { enums::ZWaveProxyRequestType type{}; const uint8_t *data{nullptr}; uint16_t data_len{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -3005,8 +2996,8 @@ class ListEntitiesInfraredResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_infrared_response"; } #endif uint32_t capabilities{0}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -3052,8 +3043,8 @@ class InfraredRFReceiveEvent final : public ProtoMessage { #endif uint32_t key{0}; const std::vector *timings{}; - void encode(ProtoWriteBuffer &buffer) const override; - void calculate_size(ProtoSize &size) const override; + void encode(ProtoWriteBuffer &buffer) const; + void calculate_size(ProtoSize &size) const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 1441507406d..e70b97196b4 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -19,14 +19,6 @@ class APIServerConnectionBase : public ProtoService { public: #endif - bool send_message(const ProtoMessage &msg, uint8_t message_type) { -#ifdef HAS_PROTO_MESSAGE_DUMP - DumpBuffer dump_buf; - this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); -#endif - return this->send_message_impl(msg, message_type); - } - virtual void on_hello_request(const HelloRequest &value){}; virtual void on_disconnect_request(){}; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 0352d7347bb..40920099503 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -363,7 +363,7 @@ void APIServer::on_zwave_proxy_request(const esphome::api::ProtoMessage &msg) { // We could add code to manage a second subscription type, but, since this message type is // very infrequent and small, we simply send it to all clients for (auto &c : this->clients_) - c->send_message(msg, api::ZWaveProxyRequest::MESSAGE_TYPE); + c->send_message(msg); } #endif @@ -531,7 +531,7 @@ bool APIServer::update_noise_psk_(const SavedNoisePsk &new_psk, const LogString this->set_noise_psk(active_psk); for (auto &c : this->clients_) { DisconnectRequest req; - c->send_message(req, DisconnectRequest::MESSAGE_TYPE); + c->send_message(req); } }); } @@ -631,7 +631,7 @@ void APIServer::on_shutdown() { // Send disconnect requests to all connected clients for (auto &c : this->clients_) { DisconnectRequest req; - if (!c->send_message(req, DisconnectRequest::MESSAGE_TYPE)) { + if (!c->send_message(req)) { // If we can't send the disconnect request directly (tx_buffer full), // schedule it at the front of the batch so it will be sent with priority c->schedule_message_front_(nullptr, DisconnectRequest::MESSAGE_TYPE, DisconnectRequest::ESTIMATED_SIZE); diff --git a/esphome/components/api/list_entities.cpp b/esphome/components/api/list_entities.cpp index fe43a47c3b7..0a94c1699b1 100644 --- a/esphome/components/api/list_entities.cpp +++ b/esphome/components/api/list_entities.cpp @@ -94,7 +94,7 @@ ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(clie #ifdef USE_API_USER_DEFINED_ACTIONS bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) { auto resp = service->encode_list_service_response(); - return this->client_->send_message(resp, ListEntitiesServicesResponse::MESSAGE_TYPE); + return this->client_->send_message(resp); } #endif diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 750fff08102..fb9bb9230c1 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -364,7 +364,8 @@ class ProtoWriteBuffer { /// Encode a packed repeated sint32 field (zero-copy from vector) void encode_packed_sint32(uint32_t field_id, const std::vector &values); /// Encode a nested message field (force=true for repeated, false for singular) - void encode_message(uint32_t field_id, const ProtoMessage &value, bool force = true); + /// Templated so concrete message type is preserved for direct encode/calculate_size calls. + template void encode_message(uint32_t field_id, const T &value, bool force = true); std::vector *get_buffer() const { return buffer_; } protected: @@ -452,20 +453,19 @@ class DumpBuffer { class ProtoMessage { public: - // Default implementation for messages with no fields - virtual void encode(ProtoWriteBuffer &buffer) const {} - // Default implementation for messages with no fields - virtual void calculate_size(ProtoSize &size) const {} - // Convenience: calculate and return size directly (defined after ProtoSize) - uint32_t calculated_size() const; + // Non-virtual defaults for messages with no fields. + // Concrete message classes hide these with their own implementations. + // All call sites use templates to preserve the concrete type, so virtual + // dispatch is not needed. This eliminates per-message vtable entries for + // encode/calculate_size, saving ~1.3 KB of flash across all message types. + void encode(ProtoWriteBuffer &buffer) const {} + void calculate_size(ProtoSize &size) const {} #ifdef HAS_PROTO_MESSAGE_DUMP virtual const char *dump_to(DumpBuffer &out) const = 0; virtual const char *message_name() const { return "unknown"; } #endif - protected: // Non-virtual: messages are never deleted polymorphically. - // Protected prevents accidental `delete base_ptr` (compile error). ~ProtoMessage() = default; }; @@ -842,7 +842,7 @@ class ProtoSize { * * @param message The nested message object */ - inline void add_message_object(uint32_t field_id_size, const ProtoMessage &message) { + template inline void add_message_object(uint32_t field_id_size, const T &message) { // Calculate nested message size by creating a temporary ProtoSize ProtoSize nested_calc; message.calculate_size(nested_calc); @@ -857,7 +857,7 @@ class ProtoSize { * * @param message The nested message object */ - inline void add_message_object_force(uint32_t field_id_size, const ProtoMessage &message) { + template inline void add_message_object_force(uint32_t field_id_size, const T &message) { // Calculate nested message size by creating a temporary ProtoSize ProtoSize nested_calc; message.calculate_size(nested_calc); @@ -924,9 +924,11 @@ class ProtoSize { // Implementation of methods that depend on ProtoSize being fully defined -inline uint32_t ProtoMessage::calculated_size() const { +// Free template to calculate encoded size of any message type. +// Replaces the former virtual ProtoMessage::calculated_size() member. +template inline uint32_t calculated_size_of(const T &msg) { ProtoSize size; - this->calculate_size(size); + msg.calculate_size(size); return size.get_size(); } @@ -950,7 +952,7 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std: } // Implementation of encode_message - must be after ProtoMessage is defined -inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessage &value, bool force) { +template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { // Calculate the message size first ProtoSize msg_size; value.calculate_size(msg_size); @@ -993,14 +995,6 @@ class ProtoService { virtual void on_no_setup_connection() = 0; virtual bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) = 0; virtual void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) = 0; - /** - * Send a protobuf message by calculating its size, allocating a buffer, encoding, and sending. - * This is the implementation method - callers should use send_message() which adds logging. - * @param msg The protobuf message to send. - * @param message_type The message type identifier. - * @return True if the message was sent successfully, false otherwise. - */ - virtual bool send_message_impl(const ProtoMessage &msg, uint8_t message_type) = 0; // Authentication helper methods inline bool check_connection_setup_() { diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 60f56fda547..981898f2404 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -333,7 +333,7 @@ void BluetoothConnection::send_service_for_discovery_() { } // Send the message with dynamically batched services - api_conn->send_message(resp, api::BluetoothGATTGetServicesResponse::MESSAGE_TYPE); + api_conn->send_message(resp); } void BluetoothConnection::log_connection_error_(const char *operation, esp_gatt_status_t status) { @@ -419,7 +419,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.address = this->address_; resp.handle = param->read.handle; resp.set_data(param->read.value, param->read.value_len); - this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTReadResponse::MESSAGE_TYPE); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_WRITE_CHAR_EVT: @@ -432,7 +432,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTWriteResponse resp; resp.address = this->address_; resp.handle = param->write.handle; - this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTWriteResponse::MESSAGE_TYPE); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { @@ -445,7 +445,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->unreg_for_notify.handle; - this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTNotifyResponse::MESSAGE_TYPE); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_REG_FOR_NOTIFY_EVT: { @@ -458,7 +458,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTNotifyResponse resp; resp.address = this->address_; resp.handle = param->reg_for_notify.handle; - this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTNotifyResponse::MESSAGE_TYPE); + this->proxy_->get_api_connection()->send_message(resp); break; } case ESP_GATTC_NOTIFY_EVT: { @@ -468,7 +468,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga resp.address = this->address_; resp.handle = param->notify.handle; resp.set_data(param->notify.value, param->notify.value_len); - this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTNotifyDataResponse::MESSAGE_TYPE); + this->proxy_->get_api_connection()->send_message(resp); break; } default: diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index d45377b3f67..257686943dd 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -44,7 +44,7 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta resp.configured_mode = this->configured_scan_active_ ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE; - this->api_connection_->send_message(resp, api::BluetoothScannerStateResponse::MESSAGE_TYPE); + this->api_connection_->send_message(resp); } void BluetoothProxy::log_connection_request_ignored_(BluetoothConnection *connection, espbt::ClientState state) { @@ -112,7 +112,7 @@ void BluetoothProxy::flush_pending_advertisements() { return; // Send the message - this->api_connection_->send_message(this->response_, api::BluetoothLERawAdvertisementsResponse::MESSAGE_TYPE); + this->api_connection_->send_message(this->response_); ESP_LOGV(TAG, "Sent batch of %u BLE advertisements", this->response_.advertisements_len); @@ -269,7 +269,7 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest call.success = ret == ESP_OK; call.error = ret; - this->api_connection_->send_message(call, api::BluetoothDeviceClearCacheResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); break; } @@ -389,7 +389,7 @@ void BluetoothProxy::send_device_connection(uint64_t address, bool connected, ui call.connected = connected; call.mtu = mtu; call.error = error; - this->api_connection_->send_message(call, api::BluetoothDeviceConnectionResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); } void BluetoothProxy::send_connections_free() { if (this->api_connection_ != nullptr) { @@ -398,7 +398,7 @@ void BluetoothProxy::send_connections_free() { } void BluetoothProxy::send_connections_free(api::APIConnection *api_connection) { - api_connection->send_message(this->connections_free_response_, api::BluetoothConnectionsFreeResponse::MESSAGE_TYPE); + api_connection->send_message(this->connections_free_response_); } void BluetoothProxy::send_gatt_services_done(uint64_t address) { @@ -406,7 +406,7 @@ void BluetoothProxy::send_gatt_services_done(uint64_t address) { return; api::BluetoothGATTGetServicesDoneResponse call; call.address = address; - this->api_connection_->send_message(call, api::BluetoothGATTGetServicesDoneResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); } void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_t error) { @@ -416,7 +416,7 @@ void BluetoothProxy::send_gatt_error(uint64_t address, uint16_t handle, esp_err_ call.address = address; call.handle = handle; call.error = error; - this->api_connection_->send_message(call, api::BluetoothGATTWriteResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); } void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_t error) { @@ -425,7 +425,7 @@ void BluetoothProxy::send_device_pairing(uint64_t address, bool paired, esp_err_ call.paired = paired; call.error = error; - this->api_connection_->send_message(call, api::BluetoothDevicePairingResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); } void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_err_t error) { @@ -434,7 +434,7 @@ void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_e call.success = success; call.error = error; - this->api_connection_->send_message(call, api::BluetoothDeviceUnpairingResponse::MESSAGE_TYPE); + this->api_connection_->send_message(call); } void BluetoothProxy::bluetooth_scanner_set_mode(bool active) { diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index d6cbfd4b215..51d52a8af8d 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -251,8 +251,7 @@ void VoiceAssistant::loop() { } #endif - if (this->api_client_ == nullptr || - !this->api_client_->send_message(msg, api::VoiceAssistantRequest::MESSAGE_TYPE)) { + if (this->api_client_ == nullptr || !this->api_client_->send_message(msg)) { ESP_LOGW(TAG, "Could not request start"); this->error_trigger_.trigger("not-connected", "Could not request start"); this->continuous_ = false; @@ -275,7 +274,7 @@ void VoiceAssistant::loop() { api::VoiceAssistantAudio msg; msg.data = this->send_buffer_; msg.data_len = read_bytes; - this->api_client_->send_message(msg, api::VoiceAssistantAudio::MESSAGE_TYPE); + this->api_client_->send_message(msg); } else { if (!this->udp_socket_running_) { if (!this->start_udp_socket_()) { @@ -354,7 +353,7 @@ void VoiceAssistant::loop() { api::VoiceAssistantAnnounceFinished msg; msg.success = true; - this->api_client_->send_message(msg, api::VoiceAssistantAnnounceFinished::MESSAGE_TYPE); + this->api_client_->send_message(msg); break; } } @@ -612,7 +611,7 @@ void VoiceAssistant::signal_stop_() { ESP_LOGD(TAG, "Signaling stop"); api::VoiceAssistantRequest msg; msg.start = false; - this->api_client_->send_message(msg, api::VoiceAssistantRequest::MESSAGE_TYPE); + this->api_client_->send_message(msg); } void VoiceAssistant::start_playback_timeout_() { @@ -622,7 +621,7 @@ void VoiceAssistant::start_playback_timeout_() { api::VoiceAssistantAnnounceFinished msg; msg.success = true; - this->api_client_->send_message(msg, api::VoiceAssistantAnnounceFinished::MESSAGE_TYPE); + this->api_client_->send_message(msg); }); } diff --git a/esphome/components/zwave_proxy/zwave_proxy.cpp b/esphome/components/zwave_proxy/zwave_proxy.cpp index 8506b19e7f4..a6fb453ae53 100644 --- a/esphome/components/zwave_proxy/zwave_proxy.cpp +++ b/esphome/components/zwave_proxy/zwave_proxy.cpp @@ -119,7 +119,7 @@ void ZWaveProxy::process_uart_() { // If this is a data frame, use frame length indicator + 2 (for SoF + checksum), else assume 1 for ACK/NAK/CAN this->outgoing_proto_msg_.data_len = this->buffer_[0] == ZWAVE_FRAME_TYPE_START ? this->buffer_[1] + 2 : 1; } - this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE); + this->api_connection_->send_message(this->outgoing_proto_msg_); } } } @@ -209,7 +209,7 @@ void ZWaveProxy::send_homeid_changed_msg_(api::APIConnection *conn) { msg.data_len = this->home_id_.size(); if (conn != nullptr) { // Send to specific connection - conn->send_message(msg, api::ZWaveProxyRequest::MESSAGE_TYPE); + conn->send_message(msg); } else if (api::global_api_server != nullptr) { // We could add code to manage a second subscription type, but, since this message is // very infrequent and small, we simply send it to all clients @@ -342,7 +342,7 @@ void ZWaveProxy::parse_start_(uint8_t byte) { this->buffer_[0] = byte; this->outgoing_proto_msg_.data = this->buffer_.data(); this->outgoing_proto_msg_.data_len = 1; - this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE); + this->api_connection_->send_message(this->outgoing_proto_msg_); } } diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 9c9cda4d36e..9f4d19cadcc 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -2233,7 +2233,7 @@ def build_message_type( o += indent("\n".join(encode)) + "\n" o += "}\n" cpp += o - prot = "void encode(ProtoWriteBuffer &buffer) const override;" + prot = "void encode(ProtoWriteBuffer &buffer) const;" public_content.append(prot) # If no fields to encode or message doesn't need encoding, the default implementation in ProtoMessage will be used @@ -2249,7 +2249,7 @@ def build_message_type( o += indent("\n".join(size_calc)) + "\n" o += "}\n" cpp += o - prot = "void calculate_size(ProtoSize &size) const override;" + prot = "void calculate_size(ProtoSize &size) const;" public_content.append(prot) # If no fields to calculate size for or message doesn't need encoding, the default implementation in ProtoMessage will be used @@ -2933,14 +2933,8 @@ static const char *const TAG = "api.service"; hpp += " public:\n" hpp += "#endif\n\n" - # Add non-template send_message method - hpp += " bool send_message(const ProtoMessage &msg, uint8_t message_type) {\n" - hpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" - hpp += " DumpBuffer dump_buf;\n" - hpp += " this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf));\n" - hpp += "#endif\n" - hpp += " return this->send_message_impl(msg, message_type);\n" - hpp += " }\n\n" + # send_message is now a template on APIConnection directly + # No non-template send_message method needed here # Add logging helper method implementations to cpp cpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n" From 6a66ab74067b699c8651ab8f51503a09b11de6c9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 17:23:38 -1000 Subject: [PATCH 06/42] tweak --- esphome/components/api/api_connection.cpp | 31 ++++++++++---- esphome/components/api/api_connection.h | 50 ++++++++++------------- 2 files changed, 45 insertions(+), 36 deletions(-) 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 From cfbe5904ccccad7d67de2612ed9be9f899694a7d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 17:31:43 -1000 Subject: [PATCH 07/42] non-template cores --- esphome/components/api/proto.h | 49 +++++++++++----------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index fb9bb9230c1..b0e38cf721d 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -366,6 +366,9 @@ class ProtoWriteBuffer { /// Encode a nested message field (force=true for repeated, false for singular) /// Templated so concrete message type is preserved for direct encode/calculate_size calls. template void encode_message(uint32_t field_id, const T &value, bool force = true); + // Non-template core for encode_message — all buffer work happens here + void encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value, + void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force); std::vector *get_buffer() const { return buffer_; } protected: @@ -843,28 +846,11 @@ class ProtoSize { * @param message The nested message object */ template inline void add_message_object(uint32_t field_id_size, const T &message) { - // Calculate nested message size by creating a temporary ProtoSize - ProtoSize nested_calc; - message.calculate_size(nested_calc); - uint32_t nested_size = nested_calc.get_size(); - - // Use the base implementation with the calculated nested_size - add_message_field(field_id_size, nested_size); + add_message_field(field_id_size, calculated_size_of(message)); } - /** - * @brief Calculates and adds the size of a nested message field to the total message size (force version) - * - * @param message The nested message object - */ template inline void add_message_object_force(uint32_t field_id_size, const T &message) { - // Calculate nested message size by creating a temporary ProtoSize - ProtoSize nested_calc; - message.calculate_size(nested_calc); - uint32_t nested_size = nested_calc.get_size(); - - // Use the base implementation with the calculated nested_size - add_message_field_force(field_id_size, nested_size); + add_message_field_force(field_id_size, calculated_size_of(message)); } /** @@ -953,29 +939,26 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std: // Implementation of encode_message - must be after ProtoMessage is defined template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { - // Calculate the message size first - ProtoSize msg_size; - value.calculate_size(msg_size); - uint32_t msg_length_bytes = msg_size.get_size(); + uint32_t msg_length_bytes = calculated_size_of(value); + this->encode_message_( + field_id, msg_length_bytes, &value, + [](const void *msg, ProtoWriteBuffer &buf) { static_cast(msg)->encode(buf); }, force); +} - // Skip empty singular messages (matches add_message_field which skips when nested_size == 0) - // Repeated messages (force=true) are always encoded since an empty item is meaningful +// Non-template core for encode_message +inline void ProtoWriteBuffer::encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value, + void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force) { if (msg_length_bytes == 0 && !force) return; - - this->encode_field_raw(field_id, 2); // type 2: Length-delimited message - - // Write the length varint directly through pos_ + this->encode_field_raw(field_id, 2); this->encode_varint_raw(msg_length_bytes); - - // Encode nested message - pos_ advances directly through the reference #ifdef ESPHOME_DEBUG_API uint8_t *start = this->pos_; - value.encode(*this); + encode_fn(value, *this); if (static_cast(this->pos_ - start) != msg_length_bytes) this->debug_check_encode_size_(field_id, msg_length_bytes, this->pos_ - start); #else - value.encode(*this); + encode_fn(value, *this); #endif } From 9ba592cc426af71339591d89deec21b3d6daba98 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 17:40:07 -1000 Subject: [PATCH 08/42] cleanup --- esphome/components/api/api_connection.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 99e5c2ee72d..cc5388f9994 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -266,7 +266,11 @@ class APIConnection final : public APIServerConnectionBase { DumpBuffer dump_buf; this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); #endif - return this->send_message_(calculated_size_of(msg), T::MESSAGE_TYPE, &encode_msg_, &msg); + if constexpr (T::ESTIMATED_SIZE == 0) { + return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop_, &msg); + } else { + return this->send_message_(calculated_size_of(msg), T::MESSAGE_TYPE, &encode_msg_, &msg); + } } void prepare_first_message_buffer(std::vector &shared_buf, size_t header_padding, size_t total_size) { @@ -327,6 +331,9 @@ class APIConnection final : public APIServerConnectionBase { static_cast(msg)->encode(buffer); } + // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) + static void encode_msg_noop_(const void *, ProtoWriteBuffer &) {} + // Non-template buffer management for send_message bool send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg); @@ -343,7 +350,11 @@ class APIConnection final : public APIServerConnectionBase { return 1; } #endif - return encode_to_buffer_(calculated_size_of(msg), &encode_msg_, &msg, conn, remaining_size); + if constexpr (T::ESTIMATED_SIZE == 0) { + return encode_to_buffer_(0, &encode_msg_noop_, &msg, conn, remaining_size); + } else { + return encode_to_buffer_(calculated_size_of(msg), &encode_msg_, &msg, conn, remaining_size); + } } // Non-template core — fills state fields and encodes From 5d3d983994fc970157deda1ee2fe14703be31f2c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 17:49:25 -1000 Subject: [PATCH 09/42] fix bug --- esphome/components/api/api_connection.cpp | 16 +++++++++------ esphome/components/api/api_connection.h | 25 +++++++++++++++-------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index d3831440c56..94bf71e00d3 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -344,17 +344,19 @@ void APIConnection::on_disconnect_response() { } uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, - uint32_t calculated_size, MessageEncodeFn encode_fn, + CalculateSizeFn size_fn, 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); + ProtoSize proto_size; + size_fn(&msg, proto_size); + return encode_to_buffer_(proto_size.get_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, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { msg.key = entity->get_object_id_hash(); @@ -380,15 +382,17 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - return encode_to_buffer_(calculated_size, encode_fn, &msg, conn, remaining_size); + ProtoSize proto_size; + size_fn(&msg, proto_size); + return encode_to_buffer_(proto_size.get_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, + EntityBase *entity, InfoResponseProtoMessage &msg, StringRef &device_class_field, CalculateSizeFn size_fn, 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); + return fill_and_encode_entity_info_(entity, msg, size_fn, 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 cc5388f9994..c7421f34584 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -260,6 +260,8 @@ class APIConnection final : public APIServerConnectionBase { // Function pointer type for type-erased message encoding using MessageEncodeFn = void (*)(const void *, ProtoWriteBuffer &); + // Function pointer type for type-erased size calculation + using CalculateSizeFn = void (*)(const void *, ProtoSize &); template bool send_message(const T &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP @@ -331,6 +333,11 @@ class APIConnection final : public APIServerConnectionBase { static_cast(msg)->encode(buffer); } + // Size thunk — converts void* back to concrete type for direct calculate_size() call + template static void calc_size_(const void *msg, ProtoSize &size) { + static_cast(msg)->calculate_size(size); + } + // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) static void encode_msg_noop_(const void *, ProtoWriteBuffer &) {} @@ -359,40 +366,40 @@ class APIConnection final : public APIServerConnectionBase { // 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); + CalculateSizeFn size_fn, 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) { - return fill_and_encode_entity_state_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); + return fill_and_encode_entity_state_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); } // 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, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size); // Thin template wrapper template static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_info_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); + return fill_and_encode_entity_info_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); } // 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); + StringRef &device_class_field, CalculateSizeFn size_fn, + 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) { - return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, calculated_size_of(msg), + return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, &calc_size_, &encode_msg_, conn, remaining_size); } From a7b61b1061c9280ce015a255ce81ec623e7a2ee4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 18:22:23 -1000 Subject: [PATCH 10/42] twea --- esphome/components/api/api_connection.cpp | 8 +- esphome/components/api/api_connection.h | 10 +- esphome/components/api/api_pb2.cpp | 360 +++++++++++++----- esphome/components/api/api_pb2.h | 185 ++++----- esphome/components/api/proto.h | 14 +- .../bluetooth_proxy/bluetooth_connection.cpp | 9 +- script/api_protobuf/api_protobuf.py | 16 +- 7 files changed, 389 insertions(+), 213 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 94bf71e00d3..c90aee50871 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -350,9 +350,7 @@ uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateR #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - ProtoSize proto_size; - size_fn(&msg, proto_size); - return encode_to_buffer_(proto_size.get_size(), encode_fn, &msg, conn, remaining_size); + return encode_to_buffer_(size_fn(&msg), encode_fn, &msg, conn, remaining_size); } uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, @@ -382,9 +380,7 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - ProtoSize proto_size; - size_fn(&msg, proto_size); - return encode_to_buffer_(proto_size.get_size(), encode_fn, &msg, conn, remaining_size); + return encode_to_buffer_(size_fn(&msg), encode_fn, &msg, conn, remaining_size); } uint16_t APIConnection::fill_and_encode_entity_info_with_device_class_( diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index c7421f34584..0a5c11ca323 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -261,7 +261,7 @@ class APIConnection final : public APIServerConnectionBase { // Function pointer type for type-erased message encoding using MessageEncodeFn = void (*)(const void *, ProtoWriteBuffer &); // Function pointer type for type-erased size calculation - using CalculateSizeFn = void (*)(const void *, ProtoSize &); + using CalculateSizeFn = uint32_t (*)(const void *); template bool send_message(const T &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP @@ -271,7 +271,7 @@ class APIConnection final : public APIServerConnectionBase { if constexpr (T::ESTIMATED_SIZE == 0) { return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop_, &msg); } else { - return this->send_message_(calculated_size_of(msg), T::MESSAGE_TYPE, &encode_msg_, &msg); + return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg_, &msg); } } @@ -334,8 +334,8 @@ class APIConnection final : public APIServerConnectionBase { } // Size thunk — converts void* back to concrete type for direct calculate_size() call - template static void calc_size_(const void *msg, ProtoSize &size) { - static_cast(msg)->calculate_size(size); + template static uint32_t calc_size_(const void *msg) { + return static_cast(msg)->calculate_size(); } // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) @@ -360,7 +360,7 @@ class APIConnection final : public APIServerConnectionBase { if constexpr (T::ESTIMATED_SIZE == 0) { return encode_to_buffer_(0, &encode_msg_noop_, &msg, conn, remaining_size); } else { - return encode_to_buffer_(calculated_size_of(msg), &encode_msg_, &msg, conn, remaining_size); + return encode_to_buffer_(msg.calculate_size(), &encode_msg_, &msg, conn, remaining_size); } } diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 9e74d5ddc7b..ed8c3e7bdea 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -37,20 +37,24 @@ void HelloResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(3, this->server_info); buffer.encode_string(4, this->name); } -void HelloResponse::calculate_size(ProtoSize &size) const { +uint32_t HelloResponse::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->api_version_major); size.add_uint32(1, this->api_version_minor); size.add_length(1, this->server_info.size()); size.add_length(1, this->name.size()); + return size.get_size(); } #ifdef USE_AREAS void AreaInfo::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, this->area_id); buffer.encode_string(2, this->name); } -void AreaInfo::calculate_size(ProtoSize &size) const { +uint32_t AreaInfo::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->area_id); size.add_length(1, this->name.size()); + return size.get_size(); } #endif #ifdef USE_DEVICES @@ -59,10 +63,12 @@ void DeviceInfo::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(2, this->name); buffer.encode_uint32(3, this->area_id); } -void DeviceInfo::calculate_size(ProtoSize &size) const { +uint32_t DeviceInfo::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->device_id); size.add_length(1, this->name.size()); size.add_uint32(1, this->area_id); + return size.get_size(); } #endif void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { @@ -120,7 +126,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(24, this->zwave_home_id); #endif } -void DeviceInfoResponse::calculate_size(ProtoSize &size) const { +uint32_t DeviceInfoResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->name.size()); size.add_length(1, this->mac_address.size()); size.add_length(1, this->esphome_version.size()); @@ -174,6 +181,7 @@ void DeviceInfoResponse::calculate_size(ProtoSize &size) const { #ifdef USE_ZWAVE_PROXY size.add_uint32(2, this->zwave_home_id); #endif + return size.get_size(); } #ifdef USE_BINARY_SENSOR void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { @@ -191,7 +199,8 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesBinarySensorResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesBinarySensorResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -205,6 +214,7 @@ void ListEntitiesBinarySensorResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -214,13 +224,15 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void BinarySensorStateResponse::calculate_size(ProtoSize &size) const { +uint32_t BinarySensorStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->state); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } #endif #ifdef USE_COVER @@ -242,7 +254,8 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(13, this->device_id); #endif } -void ListEntitiesCoverResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesCoverResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -259,6 +272,7 @@ void ListEntitiesCoverResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -269,7 +283,8 @@ void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void CoverStateResponse::calculate_size(ProtoSize &size) const { +uint32_t CoverStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_float(1, this->position); size.add_float(1, this->tilt); @@ -277,6 +292,7 @@ void CoverStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool CoverCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -337,7 +353,8 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(13, this->device_id); #endif } -void ListEntitiesFanResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesFanResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -358,6 +375,7 @@ void ListEntitiesFanResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -370,7 +388,8 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void FanStateResponse::calculate_size(ProtoSize &size) const { +uint32_t FanStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->state); size.add_bool(1, this->oscillating); @@ -380,6 +399,7 @@ void FanStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -464,7 +484,8 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(16, this->device_id); #endif } -void ListEntitiesLightResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesLightResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -488,6 +509,7 @@ void ListEntitiesLightResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(2, this->device_id); #endif + return size.get_size(); } void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -507,7 +529,8 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void LightStateResponse::calculate_size(ProtoSize &size) const { +uint32_t LightStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->state); size.add_float(1, this->brightness); @@ -524,6 +547,7 @@ void LightStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -653,7 +677,8 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void ListEntitiesSensorResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesSensorResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -670,6 +695,7 @@ void ListEntitiesSensorResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -679,13 +705,15 @@ void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void SensorStateResponse::calculate_size(ProtoSize &size) const { +uint32_t SensorStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_float(1, this->state); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } #endif #ifdef USE_SWITCH @@ -704,7 +732,8 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesSwitchResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesSwitchResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -718,6 +747,7 @@ void ListEntitiesSwitchResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -726,12 +756,14 @@ void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void SwitchStateResponse::calculate_size(ProtoSize &size) const { +uint32_t SwitchStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool SwitchCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -774,7 +806,8 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesTextSensorResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesTextSensorResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -787,6 +820,7 @@ void ListEntitiesTextSensorResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -796,13 +830,15 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void TextSensorStateResponse::calculate_size(ProtoSize &size) const { +uint32_t TextSensorStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_length(1, this->state.size()); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } #endif bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -822,9 +858,11 @@ void SubscribeLogsResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, static_cast(this->level)); buffer.encode_bytes(3, this->message_ptr_, this->message_len_); } -void SubscribeLogsResponse::calculate_size(ProtoSize &size) const { +uint32_t SubscribeLogsResponse::calculate_size() const { + ProtoSize size; size.add_uint32(1, static_cast(this->level)); size.add_length(1, this->message_len_); + return size.get_size(); } #ifdef USE_API_NOISE bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -840,16 +878,22 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD return true; } void NoiseEncryptionSetKeyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } -void NoiseEncryptionSetKeyResponse::calculate_size(ProtoSize &size) const { size.add_bool(1, this->success); } +uint32_t NoiseEncryptionSetKeyResponse::calculate_size() const { + ProtoSize size; + size.add_bool(1, this->success); + return size.get_size(); +} #endif #ifdef USE_API_HOMEASSISTANT_SERVICES void HomeassistantServiceMap::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->key); buffer.encode_string(2, this->value); } -void HomeassistantServiceMap::calculate_size(ProtoSize &size) const { +uint32_t HomeassistantServiceMap::calculate_size() const { + ProtoSize size; size.add_length(1, this->key.size()); size.add_length(1, this->value.size()); + return size.get_size(); } void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->service); @@ -873,7 +917,8 @@ void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(8, this->response_template); #endif } -void HomeassistantActionRequest::calculate_size(ProtoSize &size) const { +uint32_t HomeassistantActionRequest::calculate_size() const { + ProtoSize size; size.add_length(1, this->service.size()); size.add_repeated_message(1, this->data); size.add_repeated_message(1, this->data_template); @@ -888,6 +933,7 @@ void HomeassistantActionRequest::calculate_size(ProtoSize &size) const { #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON size.add_length(1, this->response_template.size()); #endif + return size.get_size(); } #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES @@ -929,10 +975,12 @@ void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer &buffer) const buffer.encode_string(2, this->attribute); buffer.encode_bool(3, this->once); } -void SubscribeHomeAssistantStateResponse::calculate_size(ProtoSize &size) const { +uint32_t SubscribeHomeAssistantStateResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->entity_id.size()); size.add_length(1, this->attribute.size()); size.add_bool(1, this->once); + return size.get_size(); } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -1034,9 +1082,11 @@ void ListEntitiesServicesArgument::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->name); buffer.encode_uint32(2, static_cast(this->type)); } -void ListEntitiesServicesArgument::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesServicesArgument::calculate_size() const { + ProtoSize size; size.add_length(1, this->name.size()); size.add_uint32(1, static_cast(this->type)); + return size.get_size(); } void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->name); @@ -1046,11 +1096,13 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(4, static_cast(this->supports_response)); } -void ListEntitiesServicesResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesServicesResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->name.size()); size.add_fixed32(1, this->key); size.add_repeated_message(1, this->args); size.add_uint32(1, static_cast(this->supports_response)); + return size.get_size(); } bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1165,13 +1217,15 @@ void ExecuteServiceResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(4, this->response_data, this->response_data_len); #endif } -void ExecuteServiceResponse::calculate_size(ProtoSize &size) const { +uint32_t ExecuteServiceResponse::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->call_id); size.add_bool(1, this->success); size.add_length(1, this->error_message.size()); #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON size.add_length(1, this->response_data_len); #endif + return size.get_size(); } #endif #ifdef USE_CAMERA @@ -1188,7 +1242,8 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesCameraResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesCameraResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1200,6 +1255,7 @@ void ListEntitiesCameraResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1209,13 +1265,15 @@ void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void CameraImageResponse::calculate_size(ProtoSize &size) const { +uint32_t CameraImageResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_length(1, this->data_len_); size.add_bool(1, this->done); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool CameraImageRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1275,7 +1333,8 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(27, this->feature_flags); } -void ListEntitiesClimateResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesClimateResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1329,6 +1388,7 @@ void ListEntitiesClimateResponse::calculate_size(ProtoSize &size) const { size.add_uint32(2, this->device_id); #endif size.add_uint32(2, this->feature_flags); + return size.get_size(); } void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1349,7 +1409,8 @@ void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(16, this->device_id); #endif } -void ClimateStateResponse::calculate_size(ProtoSize &size) const { +uint32_t ClimateStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_uint32(1, static_cast(this->mode)); size.add_float(1, this->current_temperature); @@ -1367,6 +1428,7 @@ void ClimateStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(2, this->device_id); #endif + return size.get_size(); } bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1481,7 +1543,8 @@ void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(12, this->supported_features); } -void ListEntitiesWaterHeaterResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1502,6 +1565,7 @@ void ListEntitiesWaterHeaterResponse::calculate_size(ProtoSize &size) const { } } size.add_uint32(1, this->supported_features); + return size.get_size(); } void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1515,7 +1579,8 @@ void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_float(7, this->target_temperature_low); buffer.encode_float(8, this->target_temperature_high); } -void WaterHeaterStateResponse::calculate_size(ProtoSize &size) const { +uint32_t WaterHeaterStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_float(1, this->current_temperature); size.add_float(1, this->target_temperature); @@ -1526,6 +1591,7 @@ void WaterHeaterStateResponse::calculate_size(ProtoSize &size) const { size.add_uint32(1, this->state); size.add_float(1, this->target_temperature_low); size.add_float(1, this->target_temperature_high); + return size.get_size(); } bool WaterHeaterCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1588,7 +1654,8 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void ListEntitiesNumberResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesNumberResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1606,6 +1673,7 @@ void ListEntitiesNumberResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1615,13 +1683,15 @@ void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void NumberStateResponse::calculate_size(ProtoSize &size) const { +uint32_t NumberStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_float(1, this->state); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool NumberCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1666,7 +1736,8 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesSelectResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesSelectResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1683,6 +1754,7 @@ void ListEntitiesSelectResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1692,13 +1764,15 @@ void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void SelectStateResponse::calculate_size(ProtoSize &size) const { +uint32_t SelectStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_length(1, this->state.size()); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool SelectCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1753,7 +1827,8 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(11, this->device_id); #endif } -void ListEntitiesSirenResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesSirenResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1772,6 +1847,7 @@ void ListEntitiesSirenResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1780,12 +1856,14 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void SirenStateResponse::calculate_size(ProtoSize &size) const { +uint32_t SirenStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool SirenCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1860,7 +1938,8 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesLockResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesLockResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1876,6 +1955,7 @@ void ListEntitiesLockResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1884,12 +1964,14 @@ void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void LockStateResponse::calculate_size(ProtoSize &size) const { +uint32_t LockStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1946,7 +2028,8 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesButtonResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesButtonResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -1959,6 +2042,7 @@ void ListEntitiesButtonResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool ButtonCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1991,12 +2075,14 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, static_cast(this->purpose)); buffer.encode_uint32(5, this->sample_bytes); } -void MediaPlayerSupportedFormat::calculate_size(ProtoSize &size) const { +uint32_t MediaPlayerSupportedFormat::calculate_size() const { + ProtoSize size; size.add_length(1, this->format.size()); size.add_uint32(1, this->sample_rate); size.add_uint32(1, this->num_channels); size.add_uint32(1, static_cast(this->purpose)); size.add_uint32(1, this->sample_bytes); + return size.get_size(); } void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->object_id); @@ -2016,7 +2102,8 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(11, this->feature_flags); } -void ListEntitiesMediaPlayerResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -2031,6 +2118,7 @@ void ListEntitiesMediaPlayerResponse::calculate_size(ProtoSize &size) const { size.add_uint32(1, this->device_id); #endif size.add_uint32(1, this->feature_flags); + return size.get_size(); } void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2041,7 +2129,8 @@ void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(5, this->device_id); #endif } -void MediaPlayerStateResponse::calculate_size(ProtoSize &size) const { +uint32_t MediaPlayerStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_uint32(1, static_cast(this->state)); size.add_float(1, this->volume); @@ -2049,6 +2138,7 @@ void MediaPlayerStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2122,21 +2212,25 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->address_type); buffer.encode_bytes(4, this->data, this->data_len); } -void BluetoothLERawAdvertisement::calculate_size(ProtoSize &size) const { +uint32_t BluetoothLERawAdvertisement::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_sint32(1, this->rssi); size.add_uint32(1, this->address_type); size.add_length(1, this->data_len); + return size.get_size(); } void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer &buffer) const { for (uint16_t i = 0; i < this->advertisements_len; i++) { buffer.encode_message(1, this->advertisements[i]); } } -void BluetoothLERawAdvertisementsResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothLERawAdvertisementsResponse::calculate_size() const { + ProtoSize size; for (uint16_t i = 0; i < this->advertisements_len; i++) { size.add_message_object_force(1, this->advertisements[i]); } + return size.get_size(); } bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2163,11 +2257,13 @@ void BluetoothDeviceConnectionResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->mtu); buffer.encode_int32(4, this->error); } -void BluetoothDeviceConnectionResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothDeviceConnectionResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_bool(1, this->connected); size.add_uint32(1, this->mtu); size.add_int32(1, this->error); + return size.get_size(); } bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2187,13 +2283,15 @@ void BluetoothGATTDescriptor::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(2, this->handle); buffer.encode_uint32(3, this->short_uuid); } -void BluetoothGATTDescriptor::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTDescriptor::calculate_size() const { + ProtoSize size; if (this->uuid[0] != 0 || this->uuid[1] != 0) { size.add_uint64_force(1, this->uuid[0]); size.add_uint64_force(1, this->uuid[1]); } size.add_uint32(1, this->handle); size.add_uint32(1, this->short_uuid); + return size.get_size(); } void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2207,7 +2305,8 @@ void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(5, this->short_uuid); } -void BluetoothGATTCharacteristic::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTCharacteristic::calculate_size() const { + ProtoSize size; if (this->uuid[0] != 0 || this->uuid[1] != 0) { size.add_uint64_force(1, this->uuid[0]); size.add_uint64_force(1, this->uuid[1]); @@ -2216,6 +2315,7 @@ void BluetoothGATTCharacteristic::calculate_size(ProtoSize &size) const { size.add_uint32(1, this->properties); size.add_repeated_message(1, this->descriptors); size.add_uint32(1, this->short_uuid); + return size.get_size(); } void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2228,7 +2328,8 @@ void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(4, this->short_uuid); } -void BluetoothGATTService::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTService::calculate_size() const { + ProtoSize size; if (this->uuid[0] != 0 || this->uuid[1] != 0) { size.add_uint64_force(1, this->uuid[0]); size.add_uint64_force(1, this->uuid[1]); @@ -2236,6 +2337,7 @@ void BluetoothGATTService::calculate_size(ProtoSize &size) const { size.add_uint32(1, this->handle); size.add_repeated_message(1, this->characteristics); size.add_uint32(1, this->short_uuid); + return size.get_size(); } void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2243,14 +2345,20 @@ void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_message(2, it); } } -void BluetoothGATTGetServicesResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTGetServicesResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_repeated_message(1, this->services); + return size.get_size(); } void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); } -void BluetoothGATTGetServicesDoneResponse::calculate_size(ProtoSize &size) const { size.add_uint64(1, this->address); } +uint32_t BluetoothGATTGetServicesDoneResponse::calculate_size() const { + ProtoSize size; + size.add_uint64(1, this->address); + return size.get_size(); +} bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: @@ -2269,10 +2377,12 @@ void BluetoothGATTReadResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(2, this->handle); buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } -void BluetoothGATTReadResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTReadResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_uint32(1, this->handle); size.add_length(1, this->data_len_); + return size.get_size(); } bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2361,10 +2471,12 @@ void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(2, this->handle); buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } -void BluetoothGATTNotifyDataResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTNotifyDataResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_uint32(1, this->handle); size.add_length(1, this->data_len_); + return size.get_size(); } void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, this->free); @@ -2375,7 +2487,8 @@ void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { } } } -void BluetoothConnectionsFreeResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothConnectionsFreeResponse::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->free); size.add_uint32(1, this->limit); for (const auto &it : this->allocated) { @@ -2383,72 +2496,87 @@ void BluetoothConnectionsFreeResponse::calculate_size(ProtoSize &size) const { size.add_uint64_force(1, it); } } + return size.get_size(); } void BluetoothGATTErrorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); buffer.encode_int32(3, this->error); } -void BluetoothGATTErrorResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTErrorResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_uint32(1, this->handle); size.add_int32(1, this->error); + return size.get_size(); } void BluetoothGATTWriteResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); } -void BluetoothGATTWriteResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTWriteResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_uint32(1, this->handle); + return size.get_size(); } void BluetoothGATTNotifyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); } -void BluetoothGATTNotifyResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothGATTNotifyResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_uint32(1, this->handle); + return size.get_size(); } void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_bool(2, this->paired); buffer.encode_int32(3, this->error); } -void BluetoothDevicePairingResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothDevicePairingResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_bool(1, this->paired); size.add_int32(1, this->error); + return size.get_size(); } void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_bool(2, this->success); buffer.encode_int32(3, this->error); } -void BluetoothDeviceUnpairingResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothDeviceUnpairingResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_bool(1, this->success); size.add_int32(1, this->error); + return size.get_size(); } void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_bool(2, this->success); buffer.encode_int32(3, this->error); } -void BluetoothDeviceClearCacheResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothDeviceClearCacheResponse::calculate_size() const { + ProtoSize size; size.add_uint64(1, this->address); size.add_bool(1, this->success); size.add_int32(1, this->error); + return size.get_size(); } void BluetoothScannerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, static_cast(this->state)); buffer.encode_uint32(2, static_cast(this->mode)); buffer.encode_uint32(3, static_cast(this->configured_mode)); } -void BluetoothScannerStateResponse::calculate_size(ProtoSize &size) const { +uint32_t BluetoothScannerStateResponse::calculate_size() const { + ProtoSize size; size.add_uint32(1, static_cast(this->state)); size.add_uint32(1, static_cast(this->mode)); size.add_uint32(1, static_cast(this->configured_mode)); + return size.get_size(); } bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2480,10 +2608,12 @@ void VoiceAssistantAudioSettings::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(2, this->auto_gain); buffer.encode_float(3, this->volume_multiplier); } -void VoiceAssistantAudioSettings::calculate_size(ProtoSize &size) const { +uint32_t VoiceAssistantAudioSettings::calculate_size() const { + ProtoSize size; size.add_uint32(1, this->noise_suppression_level); size.add_uint32(1, this->auto_gain); size.add_float(1, this->volume_multiplier); + return size.get_size(); } void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->start); @@ -2492,12 +2622,14 @@ void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_message(4, this->audio_settings, false); buffer.encode_string(5, this->wake_word_phrase); } -void VoiceAssistantRequest::calculate_size(ProtoSize &size) const { +uint32_t VoiceAssistantRequest::calculate_size() const { + ProtoSize size; size.add_bool(1, this->start); size.add_length(1, this->conversation_id.size()); size.add_uint32(1, this->flags); size.add_message_object(1, this->audio_settings); size.add_length(1, this->wake_word_phrase.size()); + return size.get_size(); } bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2574,9 +2706,11 @@ void VoiceAssistantAudio::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(1, this->data, this->data_len); buffer.encode_bool(2, this->end); } -void VoiceAssistantAudio::calculate_size(ProtoSize &size) const { +uint32_t VoiceAssistantAudio::calculate_size() const { + ProtoSize size; size.add_length(1, this->data_len); size.add_bool(1, this->end); + return size.get_size(); } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2642,7 +2776,11 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength return true; } void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } -void VoiceAssistantAnnounceFinished::calculate_size(ProtoSize &size) const { size.add_bool(1, this->success); } +uint32_t VoiceAssistantAnnounceFinished::calculate_size() const { + ProtoSize size; + size.add_bool(1, this->success); + return size.get_size(); +} void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->id); buffer.encode_string(2, this->wake_word); @@ -2650,7 +2788,8 @@ void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(3, it, true); } } -void VoiceAssistantWakeWord::calculate_size(ProtoSize &size) const { +uint32_t VoiceAssistantWakeWord::calculate_size() const { + ProtoSize size; size.add_length(1, this->id.size()); size.add_length(1, this->wake_word.size()); if (!this->trained_languages.empty()) { @@ -2658,6 +2797,7 @@ void VoiceAssistantWakeWord::calculate_size(ProtoSize &size) const { size.add_length_force(1, it.size()); } } + return size.get_size(); } bool VoiceAssistantExternalWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2719,7 +2859,8 @@ void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer &buffer) const } buffer.encode_uint32(3, this->max_active_wake_words); } -void VoiceAssistantConfigurationResponse::calculate_size(ProtoSize &size) const { +uint32_t VoiceAssistantConfigurationResponse::calculate_size() const { + ProtoSize size; size.add_repeated_message(1, this->available_wake_words); if (!this->active_wake_words->empty()) { for (const auto &it : *this->active_wake_words) { @@ -2727,6 +2868,7 @@ void VoiceAssistantConfigurationResponse::calculate_size(ProtoSize &size) const } } size.add_uint32(1, this->max_active_wake_words); + return size.get_size(); } bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -2756,7 +2898,8 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) con buffer.encode_uint32(11, this->device_id); #endif } -void ListEntitiesAlarmControlPanelResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -2771,6 +2914,7 @@ void ListEntitiesAlarmControlPanelResponse::calculate_size(ProtoSize &size) cons #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2779,12 +2923,14 @@ void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void AlarmControlPanelStateResponse::calculate_size(ProtoSize &size) const { +uint32_t AlarmControlPanelStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2841,7 +2987,8 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesTextResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesTextResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -2857,6 +3004,7 @@ void ListEntitiesTextResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2866,13 +3014,15 @@ void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void TextStateResponse::calculate_size(ProtoSize &size) const { +uint32_t TextStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_length(1, this->state.size()); size.add_bool(1, this->missing_state); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool TextCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2922,7 +3072,8 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesDateResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesDateResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -2934,6 +3085,7 @@ void ListEntitiesDateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2945,7 +3097,8 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void DateStateResponse::calculate_size(ProtoSize &size) const { +uint32_t DateStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->missing_state); size.add_uint32(1, this->year); @@ -2954,6 +3107,7 @@ void DateStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool DateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3001,7 +3155,8 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesTimeResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesTimeResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3013,6 +3168,7 @@ void ListEntitiesTimeResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3024,7 +3180,8 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void TimeStateResponse::calculate_size(ProtoSize &size) const { +uint32_t TimeStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->missing_state); size.add_uint32(1, this->hour); @@ -3033,6 +3190,7 @@ void TimeStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool TimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3084,7 +3242,8 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesEventResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesEventResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3102,6 +3261,7 @@ void ListEntitiesEventResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void EventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3110,12 +3270,14 @@ void EventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void EventResponse::calculate_size(ProtoSize &size) const { +uint32_t EventResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_length(1, this->event_type.size()); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } #endif #ifdef USE_VALVE @@ -3136,7 +3298,8 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesValveResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesValveResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3152,6 +3315,7 @@ void ListEntitiesValveResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3161,13 +3325,15 @@ void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void ValveStateResponse::calculate_size(ProtoSize &size) const { +uint32_t ValveStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_float(1, this->position); size.add_uint32(1, static_cast(this->current_operation)); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool ValveCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3215,7 +3381,8 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesDateTimeResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesDateTimeResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3227,6 +3394,7 @@ void ListEntitiesDateTimeResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3236,13 +3404,15 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void DateTimeStateResponse::calculate_size(ProtoSize &size) const { +uint32_t DateTimeStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->missing_state); size.add_fixed32(1, this->epoch_seconds); #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool DateTimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3285,7 +3455,8 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesUpdateResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesUpdateResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3298,6 +3469,7 @@ void ListEntitiesUpdateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3314,7 +3486,8 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(11, this->device_id); #endif } -void UpdateStateResponse::calculate_size(ProtoSize &size) const { +uint32_t UpdateStateResponse::calculate_size() const { + ProtoSize size; size.add_fixed32(1, this->key); size.add_bool(1, this->missing_state); size.add_bool(1, this->in_progress); @@ -3328,6 +3501,7 @@ void UpdateStateResponse::calculate_size(ProtoSize &size) const { #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif + return size.get_size(); } bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3369,7 +3543,11 @@ bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited valu return true; } void ZWaveProxyFrame::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(1, this->data, this->data_len); } -void ZWaveProxyFrame::calculate_size(ProtoSize &size) const { size.add_length(1, this->data_len); } +uint32_t ZWaveProxyFrame::calculate_size() const { + ProtoSize size; + size.add_length(1, this->data_len); + return size.get_size(); +} bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: @@ -3396,9 +3574,11 @@ void ZWaveProxyRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, static_cast(this->type)); buffer.encode_bytes(2, this->data, this->data_len); } -void ZWaveProxyRequest::calculate_size(ProtoSize &size) const { +uint32_t ZWaveProxyRequest::calculate_size() const { + ProtoSize size; size.add_uint32(1, static_cast(this->type)); size.add_length(1, this->data_len); + return size.get_size(); } #endif #ifdef USE_INFRARED @@ -3416,7 +3596,8 @@ void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(8, this->capabilities); } -void ListEntitiesInfraredResponse::calculate_size(ProtoSize &size) const { +uint32_t ListEntitiesInfraredResponse::calculate_size() const { + ProtoSize size; size.add_length(1, this->object_id.size()); size.add_fixed32(1, this->key); size.add_length(1, this->name.size()); @@ -3429,6 +3610,7 @@ void ListEntitiesInfraredResponse::calculate_size(ProtoSize &size) const { size.add_uint32(1, this->device_id); #endif size.add_uint32(1, this->capabilities); + return size.get_size(); } #endif #ifdef USE_IR_RF @@ -3482,7 +3664,8 @@ void InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer) const { buffer.encode_sint32(3, it, true); } } -void InfraredRFReceiveEvent::calculate_size(ProtoSize &size) const { +uint32_t InfraredRFReceiveEvent::calculate_size() const { + ProtoSize size; #ifdef USE_DEVICES size.add_uint32(1, this->device_id); #endif @@ -3492,6 +3675,7 @@ void InfraredRFReceiveEvent::calculate_size(ProtoSize &size) const { size.add_sint32_force(1, it); } } + return size.get_size(); } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 84f9baa5a56..89cb1158f33 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -333,6 +333,9 @@ class InfoResponseProtoMessage : public ProtoMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif + + protected: + ~InfoResponseProtoMessage() = default; }; class StateResponseProtoMessage : public ProtoMessage { @@ -341,6 +344,9 @@ class StateResponseProtoMessage : public ProtoMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif + + protected: + ~StateResponseProtoMessage() = default; }; class CommandProtoMessage : public ProtoDecodableMessage { @@ -349,6 +355,9 @@ class CommandProtoMessage : public ProtoDecodableMessage { #ifdef USE_DEVICES uint32_t device_id{0}; #endif + + protected: + ~CommandProtoMessage() = default; }; class HelloRequest final : public ProtoDecodableMessage { public: @@ -380,7 +389,7 @@ class HelloResponse final : public ProtoMessage { StringRef server_info{}; StringRef name{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -445,7 +454,7 @@ class AreaInfo final : public ProtoMessage { uint32_t area_id{0}; StringRef name{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -460,7 +469,7 @@ class DeviceInfo final : public ProtoMessage { StringRef name{}; uint32_t area_id{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -525,7 +534,7 @@ class DeviceInfoResponse final : public ProtoMessage { uint32_t zwave_home_id{0}; #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -556,7 +565,7 @@ class ListEntitiesBinarySensorResponse final : public InfoResponseProtoMessage { StringRef device_class{}; bool is_status_binary_sensor{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -573,7 +582,7 @@ class BinarySensorStateResponse final : public StateResponseProtoMessage { bool state{false}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -595,7 +604,7 @@ class ListEntitiesCoverResponse final : public InfoResponseProtoMessage { StringRef device_class{}; bool supports_stop{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -613,7 +622,7 @@ class CoverStateResponse final : public StateResponseProtoMessage { float tilt{0.0f}; enums::CoverOperation current_operation{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -655,7 +664,7 @@ class ListEntitiesFanResponse final : public InfoResponseProtoMessage { int32_t supported_speed_count{0}; const std::vector *supported_preset_modes{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -675,7 +684,7 @@ class FanStateResponse final : public StateResponseProtoMessage { int32_t speed_level{0}; StringRef preset_mode{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -722,7 +731,7 @@ class ListEntitiesLightResponse final : public InfoResponseProtoMessage { float max_mireds{0.0f}; const FixedVector *effects{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -749,7 +758,7 @@ class LightStateResponse final : public StateResponseProtoMessage { float warm_white{0.0f}; StringRef effect{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -813,7 +822,7 @@ class ListEntitiesSensorResponse final : public InfoResponseProtoMessage { StringRef device_class{}; enums::SensorStateClass state_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -830,7 +839,7 @@ class SensorStateResponse final : public StateResponseProtoMessage { float state{0.0f}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -849,7 +858,7 @@ class ListEntitiesSwitchResponse final : public InfoResponseProtoMessage { bool assumed_state{false}; StringRef device_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -865,7 +874,7 @@ class SwitchStateResponse final : public StateResponseProtoMessage { #endif bool state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -899,7 +908,7 @@ class ListEntitiesTextSensorResponse final : public InfoResponseProtoMessage { #endif StringRef device_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -916,7 +925,7 @@ class TextSensorStateResponse final : public StateResponseProtoMessage { StringRef state{}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -955,7 +964,7 @@ class SubscribeLogsResponse final : public ProtoMessage { this->message_len_ = len; } void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -988,7 +997,7 @@ class NoiseEncryptionSetKeyResponse final : public ProtoMessage { #endif bool success{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1002,7 +1011,7 @@ class HomeassistantServiceMap final : public ProtoMessage { StringRef key{}; StringRef value{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1031,7 +1040,7 @@ class HomeassistantActionRequest final : public ProtoMessage { StringRef response_template{}; #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1075,7 +1084,7 @@ class SubscribeHomeAssistantStateResponse final : public ProtoMessage { StringRef attribute{}; bool once{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1166,7 +1175,7 @@ class ListEntitiesServicesArgument final : public ProtoMessage { StringRef name{}; enums::ServiceArgType type{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1185,7 +1194,7 @@ class ListEntitiesServicesResponse final : public ProtoMessage { FixedVector args{}; enums::SupportsResponseType supports_response{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1255,7 +1264,7 @@ class ExecuteServiceResponse final : public ProtoMessage { uint16_t response_data_len{0}; #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1272,7 +1281,7 @@ class ListEntitiesCameraResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_camera_response"; } #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1294,7 +1303,7 @@ class CameraImageResponse final : public StateResponseProtoMessage { } bool done{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1345,7 +1354,7 @@ class ListEntitiesClimateResponse final : public InfoResponseProtoMessage { float visual_max_humidity{0.0f}; uint32_t feature_flags{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1373,7 +1382,7 @@ class ClimateStateResponse final : public StateResponseProtoMessage { float current_humidity{0.0f}; float target_humidity{0.0f}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1431,7 +1440,7 @@ class ListEntitiesWaterHeaterResponse final : public InfoResponseProtoMessage { const water_heater::WaterHeaterModeMask *supported_modes{}; uint32_t supported_features{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1452,7 +1461,7 @@ class WaterHeaterStateResponse final : public StateResponseProtoMessage { float target_temperature_low{0.0f}; float target_temperature_high{0.0f}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1496,7 +1505,7 @@ class ListEntitiesNumberResponse final : public InfoResponseProtoMessage { enums::NumberMode mode{}; StringRef device_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1513,7 +1522,7 @@ class NumberStateResponse final : public StateResponseProtoMessage { float state{0.0f}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1547,7 +1556,7 @@ class ListEntitiesSelectResponse final : public InfoResponseProtoMessage { #endif const FixedVector *options{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1564,7 +1573,7 @@ class SelectStateResponse final : public StateResponseProtoMessage { StringRef state{}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1601,7 +1610,7 @@ class ListEntitiesSirenResponse final : public InfoResponseProtoMessage { bool supports_duration{false}; bool supports_volume{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1617,7 +1626,7 @@ class SirenStateResponse final : public StateResponseProtoMessage { #endif bool state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1662,7 +1671,7 @@ class ListEntitiesLockResponse final : public InfoResponseProtoMessage { bool requires_code{false}; StringRef code_format{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1678,7 +1687,7 @@ class LockStateResponse final : public StateResponseProtoMessage { #endif enums::LockState state{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1715,7 +1724,7 @@ class ListEntitiesButtonResponse final : public InfoResponseProtoMessage { #endif StringRef device_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1747,7 +1756,7 @@ class MediaPlayerSupportedFormat final : public ProtoMessage { enums::MediaPlayerFormatPurpose purpose{}; uint32_t sample_bytes{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1765,7 +1774,7 @@ class ListEntitiesMediaPlayerResponse final : public InfoResponseProtoMessage { std::vector supported_formats{}; uint32_t feature_flags{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1783,7 +1792,7 @@ class MediaPlayerStateResponse final : public StateResponseProtoMessage { float volume{0.0f}; bool muted{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1839,7 +1848,7 @@ class BluetoothLERawAdvertisement final : public ProtoMessage { uint8_t data[62]{}; uint8_t data_len{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1856,7 +1865,7 @@ class BluetoothLERawAdvertisementsResponse final : public ProtoMessage { std::array advertisements{}; uint16_t advertisements_len{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1893,7 +1902,7 @@ class BluetoothDeviceConnectionResponse final : public ProtoMessage { uint32_t mtu{0}; int32_t error{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1921,7 +1930,7 @@ class BluetoothGATTDescriptor final : public ProtoMessage { uint32_t handle{0}; uint32_t short_uuid{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1936,7 +1945,7 @@ class BluetoothGATTCharacteristic final : public ProtoMessage { FixedVector descriptors{}; uint32_t short_uuid{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1950,7 +1959,7 @@ class BluetoothGATTService final : public ProtoMessage { FixedVector characteristics{}; uint32_t short_uuid{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1967,7 +1976,7 @@ class BluetoothGATTGetServicesResponse final : public ProtoMessage { uint64_t address{0}; std::vector services{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1983,7 +1992,7 @@ class BluetoothGATTGetServicesDoneResponse final : public ProtoMessage { #endif uint64_t address{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2022,7 +2031,7 @@ class BluetoothGATTReadResponse final : public ProtoMessage { this->data_len_ = len; } void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2117,7 +2126,7 @@ class BluetoothGATTNotifyDataResponse final : public ProtoMessage { this->data_len_ = len; } void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2135,7 +2144,7 @@ class BluetoothConnectionsFreeResponse final : public ProtoMessage { uint32_t limit{0}; std::array allocated{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2153,7 +2162,7 @@ class BluetoothGATTErrorResponse final : public ProtoMessage { uint32_t handle{0}; int32_t error{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2170,7 +2179,7 @@ class BluetoothGATTWriteResponse final : public ProtoMessage { uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2187,7 +2196,7 @@ class BluetoothGATTNotifyResponse final : public ProtoMessage { uint64_t address{0}; uint32_t handle{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2205,7 +2214,7 @@ class BluetoothDevicePairingResponse final : public ProtoMessage { bool paired{false}; int32_t error{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2223,7 +2232,7 @@ class BluetoothDeviceUnpairingResponse final : public ProtoMessage { bool success{false}; int32_t error{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2241,7 +2250,7 @@ class BluetoothDeviceClearCacheResponse final : public ProtoMessage { bool success{false}; int32_t error{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2259,7 +2268,7 @@ class BluetoothScannerStateResponse final : public ProtoMessage { enums::BluetoothScannerMode mode{}; enums::BluetoothScannerMode configured_mode{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2305,7 +2314,7 @@ class VoiceAssistantAudioSettings final : public ProtoMessage { uint32_t auto_gain{0}; float volume_multiplier{0.0f}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2325,7 +2334,7 @@ class VoiceAssistantRequest final : public ProtoMessage { VoiceAssistantAudioSettings audio_settings{}; StringRef wake_word_phrase{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2387,7 +2396,7 @@ class VoiceAssistantAudio final : public ProtoDecodableMessage { uint16_t data_len{0}; bool end{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2445,7 +2454,7 @@ class VoiceAssistantAnnounceFinished final : public ProtoMessage { #endif bool success{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2458,7 +2467,7 @@ class VoiceAssistantWakeWord final : public ProtoMessage { StringRef wake_word{}; std::vector trained_languages{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2508,7 +2517,7 @@ class VoiceAssistantConfigurationResponse final : public ProtoMessage { const std::vector *active_wake_words{}; uint32_t max_active_wake_words{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2543,7 +2552,7 @@ class ListEntitiesAlarmControlPanelResponse final : public InfoResponseProtoMess bool requires_code{false}; bool requires_code_to_arm{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2559,7 +2568,7 @@ class AlarmControlPanelStateResponse final : public StateResponseProtoMessage { #endif enums::AlarmControlPanelState state{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2598,7 +2607,7 @@ class ListEntitiesTextResponse final : public InfoResponseProtoMessage { StringRef pattern{}; enums::TextMode mode{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2615,7 +2624,7 @@ class TextStateResponse final : public StateResponseProtoMessage { StringRef state{}; bool missing_state{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2649,7 +2658,7 @@ class ListEntitiesDateResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_date_response"; } #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2668,7 +2677,7 @@ class DateStateResponse final : public StateResponseProtoMessage { uint32_t month{0}; uint32_t day{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2703,7 +2712,7 @@ class ListEntitiesTimeResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_time_response"; } #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2722,7 +2731,7 @@ class TimeStateResponse final : public StateResponseProtoMessage { uint32_t minute{0}; uint32_t second{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2759,7 +2768,7 @@ class ListEntitiesEventResponse final : public InfoResponseProtoMessage { StringRef device_class{}; const FixedVector *event_types{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2775,7 +2784,7 @@ class EventResponse final : public StateResponseProtoMessage { #endif StringRef event_type{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2796,7 +2805,7 @@ class ListEntitiesValveResponse final : public InfoResponseProtoMessage { bool supports_position{false}; bool supports_stop{false}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2813,7 +2822,7 @@ class ValveStateResponse final : public StateResponseProtoMessage { float position{0.0f}; enums::ValveOperation current_operation{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2848,7 +2857,7 @@ class ListEntitiesDateTimeResponse final : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_date_time_response"; } #endif void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2865,7 +2874,7 @@ class DateTimeStateResponse final : public StateResponseProtoMessage { bool missing_state{false}; uint32_t epoch_seconds{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2899,7 +2908,7 @@ class ListEntitiesUpdateResponse final : public InfoResponseProtoMessage { #endif StringRef device_class{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2923,7 +2932,7 @@ class UpdateStateResponse final : public StateResponseProtoMessage { StringRef release_summary{}; StringRef release_url{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2958,7 +2967,7 @@ class ZWaveProxyFrame final : public ProtoDecodableMessage { const uint8_t *data{nullptr}; uint16_t data_len{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2977,7 +2986,7 @@ class ZWaveProxyRequest final : public ProtoDecodableMessage { const uint8_t *data{nullptr}; uint16_t data_len{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2997,7 +3006,7 @@ class ListEntitiesInfraredResponse final : public InfoResponseProtoMessage { #endif uint32_t capabilities{0}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -3044,7 +3053,7 @@ class InfraredRFReceiveEvent final : public ProtoMessage { uint32_t key{0}; const std::vector *timings{}; void encode(ProtoWriteBuffer &buffer) const; - void calculate_size(ProtoSize &size) const; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index b0e38cf721d..58820ca659d 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -462,7 +462,7 @@ class ProtoMessage { // dispatch is not needed. This eliminates per-message vtable entries for // encode/calculate_size, saving ~1.3 KB of flash across all message types. void encode(ProtoWriteBuffer &buffer) const {} - void calculate_size(ProtoSize &size) const {} + uint32_t calculate_size() const { return 0; } #ifdef HAS_PROTO_MESSAGE_DUMP virtual const char *dump_to(DumpBuffer &out) const = 0; virtual const char *message_name() const { return "unknown"; } @@ -846,11 +846,11 @@ class ProtoSize { * @param message The nested message object */ template inline void add_message_object(uint32_t field_id_size, const T &message) { - add_message_field(field_id_size, calculated_size_of(message)); + add_message_field(field_id_size, message.calculate_size()); } template inline void add_message_object_force(uint32_t field_id_size, const T &message) { - add_message_field_force(field_id_size, calculated_size_of(message)); + add_message_field_force(field_id_size, message.calculate_size()); } /** @@ -912,11 +912,7 @@ class ProtoSize { // Free template to calculate encoded size of any message type. // Replaces the former virtual ProtoMessage::calculated_size() member. -template inline uint32_t calculated_size_of(const T &msg) { - ProtoSize size; - msg.calculate_size(size); - return size.get_size(); -} +template inline uint32_t calculated_size_of(const T &msg) { return msg.calculate_size(); } // Implementation of encode_packed_sint32 - must be after ProtoSize is defined inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std::vector &values) { @@ -939,7 +935,7 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std: // Implementation of encode_message - must be after ProtoMessage is defined template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { - uint32_t msg_length_bytes = calculated_size_of(value); + uint32_t msg_length_bytes = value.calculate_size(); this->encode_message_( field_id, msg_length_bytes, &value, [](const void *msg, ProtoWriteBuffer &buf) { static_cast(msg)->encode(buf); }, force); diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 981898f2404..967a96a08c5 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -183,10 +183,7 @@ void BluetoothConnection::send_service_for_discovery_() { static constexpr size_t MAX_PACKET_SIZE = 1360; // Keep running total of actual message size - size_t current_size = 0; - api::ProtoSize size; - resp.calculate_size(size); - current_size = size.get_size(); + size_t current_size = resp.calculate_size(); while (this->send_service_ < this->service_count_) { esp_gattc_service_elem_t service_result; @@ -302,9 +299,7 @@ void BluetoothConnection::send_service_for_discovery_() { } // end if (total_char_count > 0) // Calculate the actual size of just this service - api::ProtoSize service_sizer; - service_resp.calculate_size(service_sizer); - size_t service_size = service_sizer.get_size() + 1; // +1 for field tag + size_t service_size = service_resp.calculate_size() + 1; // +1 for field tag // Check if adding this service would exceed the limit if (current_size + service_size > MAX_PACKET_SIZE) { diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 9f4d19cadcc..9906982c7f5 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -2239,17 +2239,13 @@ def build_message_type( # Add calculate_size method only if this message needs encoding and has fields if needs_encode and size_calc: - o = f"void {desc.name}::calculate_size(ProtoSize &size) const {{" - # For a single field, just inline it for simplicity - if len(size_calc) == 1 and len(size_calc[0]) + len(o) + 3 < 120: - o += f" {size_calc[0]} }}\n" - else: - # For multiple fields - o += "\n" - o += indent("\n".join(size_calc)) + "\n" - o += "}\n" + o = f"uint32_t {desc.name}::calculate_size() const {{\n" + o += " ProtoSize size;\n" + o += indent("\n".join(size_calc)) + "\n" + o += " return size.get_size();\n" + o += "}\n" cpp += o - prot = "void calculate_size(ProtoSize &size) const;" + prot = "uint32_t calculate_size() const;" public_content.append(prot) # If no fields to calculate size for or message doesn't need encoding, the default implementation in ProtoMessage will be used From 0a816192b2182009bb68d5a1947364c30e78f6d9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 18:32:18 -1000 Subject: [PATCH 11/42] restore comments to reduce diff churn --- esphome/components/api/api_connection.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index c90aee50871..64d4b37d8cd 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -356,12 +356,14 @@ uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateR uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { + // Set common fields that are shared by all entity types 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 + // Buffer must remain in scope until encode_to_buffer_ is called 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); @@ -371,6 +373,7 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes msg.name = entity->get_name(); } + // Set common EntityBase properties #ifdef USE_ENTITY_ICON char icon_buf[MAX_ICON_LENGTH]; msg.icon = StringRef(entity->get_icon_to(icon_buf)); @@ -1871,25 +1874,41 @@ bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, M encode_fn(msg, buffer); return this->send_buffer(ProtoWriteBuffer{&shared_buf}, message_type); } +// Encodes a message to the buffer and returns the total number of bytes used, +// including header and footer overhead. Returns 0 if the message doesn't fit. uint16_t APIConnection::encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, APIConnection *conn, uint32_t remaining_size) { + // Cache frame sizes to avoid repeated virtual calls const uint8_t header_padding = conn->helper_->frame_header_padding(); const uint8_t footer_size = conn->helper_->frame_footer_size(); + + // Calculate total size with padding for buffer allocation size_t total_calculated_size = calculated_size + header_padding + footer_size; + + // Check if it fits if (total_calculated_size > remaining_size) - return 0; + return 0; // Doesn't fit + std::vector &shared_buf = conn->parent_->get_shared_buffer_ref(); + if (conn->flags_.batch_first_message) { + // First message - buffer already prepared by caller, just clear flag conn->flags_.batch_first_message = false; } else { + // Batch message second or later + // Add padding for previous message footer + this message header size_t current_size = shared_buf.size(); shared_buf.reserve(current_size + total_calculated_size); shared_buf.resize(current_size + footer_size + header_padding); } + + // Pre-resize buffer to include payload, then encode through raw pointer size_t write_start = shared_buf.size(); shared_buf.resize(write_start + calculated_size); ProtoWriteBuffer buffer{&shared_buf, write_start}; encode_fn(msg, buffer); + + // Return total size (header + payload + footer) return static_cast(header_padding + calculated_size + footer_size); } bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) { From 1e7eba1e904055ab8dd12c9a6ce5a34bb9e91e08 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 18:35:00 -1000 Subject: [PATCH 12/42] tidy --- esphome/components/api/api_connection.cpp | 32 ++++++------ esphome/components/api/api_connection.h | 60 +++++++++++------------ esphome/components/api/api_server.cpp | 2 +- esphome/components/api/api_server.h | 2 +- esphome/components/api/proto.h | 10 ++-- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 64d4b37d8cd..4ff5ead8936 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -343,19 +343,19 @@ void APIConnection::on_disconnect_response() { this->flags_.remove = true; } -uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, - CalculateSizeFn size_fn, MessageEncodeFn encode_fn, - APIConnection *conn, uint32_t remaining_size) { +uint16_t APIConnection::fill_and_encode_entity_state(EntityBase *entity, StateResponseProtoMessage &msg, + CalculateSizeFn size_fn, 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_(size_fn(&msg), encode_fn, &msg, conn, remaining_size); + return encode_to_buffer(size_fn(&msg), encode_fn, &msg, conn, remaining_size); } -uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, - CalculateSizeFn size_fn, MessageEncodeFn encode_fn, - APIConnection *conn, uint32_t remaining_size) { +uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, + APIConnection *conn, uint32_t remaining_size) { // Set common fields that are shared by all entity types msg.key = entity->get_object_id_hash(); @@ -363,7 +363,7 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes // 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 - // Buffer must remain in scope until encode_to_buffer_ is called + // Buffer must remain in scope until encode_to_buffer is called 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); @@ -383,15 +383,17 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - return encode_to_buffer_(size_fn(&msg), encode_fn, &msg, conn, remaining_size); + return encode_to_buffer(size_fn(&msg), 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, CalculateSizeFn size_fn, - MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { +uint16_t APIConnection::fill_and_encode_entity_info_with_device_class(EntityBase *entity, InfoResponseProtoMessage &msg, + StringRef &device_class_field, + CalculateSizeFn size_fn, + 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, size_fn, encode_fn, conn, remaining_size); + return fill_and_encode_entity_info(entity, msg, size_fn, encode_fn, conn, remaining_size); } #ifdef USE_BINARY_SENSOR @@ -1876,8 +1878,8 @@ bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, M } // Encodes a message to the buffer and returns the total number of bytes used, // including header and footer overhead. Returns 0 if the message doesn't fit. -uint16_t APIConnection::encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, - APIConnection *conn, uint32_t remaining_size) { +uint16_t APIConnection::encode_to_buffer(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, + APIConnection *conn, uint32_t remaining_size) { // Cache frame sizes to avoid repeated virtual calls const uint8_t header_padding = conn->helper_->frame_header_padding(); const uint8_t footer_size = conn->helper_->frame_footer_size(); diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 0a5c11ca323..ddf2853438b 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -269,9 +269,9 @@ class APIConnection final : public APIServerConnectionBase { this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); #endif if constexpr (T::ESTIMATED_SIZE == 0) { - return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop_, &msg); + return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop, &msg); } else { - return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg_, &msg); + return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg, &msg); } } @@ -339,14 +339,14 @@ class APIConnection final : public APIServerConnectionBase { } // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) - static void encode_msg_noop_(const void *, ProtoWriteBuffer &) {} + static void encode_msg_noop(const void *, ProtoWriteBuffer &) {} // Non-template buffer management for send_message bool send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg); // Non-template buffer management for batch encoding - static uint16_t encode_to_buffer_(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, - APIConnection *conn, uint32_t remaining_size); + static uint16_t encode_to_buffer(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, + APIConnection *conn, uint32_t remaining_size); // Thin template wrapper — computes size, delegates buffer work to non-template helper template static uint16_t encode_message_to_buffer(T &msg, APIConnection *conn, uint32_t remaining_size) { @@ -358,49 +358,49 @@ class APIConnection final : public APIServerConnectionBase { } #endif if constexpr (T::ESTIMATED_SIZE == 0) { - return encode_to_buffer_(0, &encode_msg_noop_, &msg, conn, remaining_size); + return encode_to_buffer(0, &encode_msg_noop, &msg, conn, remaining_size); } else { - return encode_to_buffer_(msg.calculate_size(), &encode_msg_, &msg, conn, remaining_size); + return encode_to_buffer(msg.calculate_size(), &encode_msg, &msg, conn, remaining_size); } } // Non-template core — fills state fields and encodes - static uint16_t fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, - CalculateSizeFn size_fn, 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) { - return fill_and_encode_entity_state_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); - } - - // Non-template core — fills info fields, allocates buffers, and encodes - static uint16_t fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, + static uint16_t fill_and_encode_entity_state(EntityBase *entity, StateResponseProtoMessage &msg, CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size); // Thin template wrapper template - static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, - uint32_t remaining_size) { - return fill_and_encode_entity_info_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); + static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn, + uint32_t remaining_size) { + return fill_and_encode_entity_state(entity, msg, &calc_size, &encode_msg, conn, remaining_size); } - // 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, CalculateSizeFn size_fn, - MessageEncodeFn encode_fn, APIConnection *conn, - uint32_t remaining_size); + // Non-template core — fills info fields, allocates buffers, and encodes + static uint16_t fill_and_encode_entity_info(EntityBase *entity, InfoResponseProtoMessage &msg, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, + uint32_t remaining_size); + + // Thin template wrapper + template + static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, + uint32_t remaining_size) { + return fill_and_encode_entity_info(entity, msg, &calc_size, &encode_msg, conn, remaining_size); + } + + // 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, CalculateSizeFn size_fn, + 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) { - return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, &calc_size_, - &encode_msg_, conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(entity, msg, device_class_field, &calc_size, &encode_msg, + conn, remaining_size); } #ifdef USE_VOICE_ASSISTANT diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 40920099503..06816fe3e05 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -359,7 +359,7 @@ void APIServer::on_update(update::UpdateEntity *obj) { #endif #ifdef USE_ZWAVE_PROXY -void APIServer::on_zwave_proxy_request(const esphome::api::ProtoMessage &msg) { +void APIServer::on_zwave_proxy_request(const ZWaveProxyRequest &msg) { // We could add code to manage a second subscription type, but, since this message type is // very infrequent and small, we simply send it to all clients for (auto &c : this->clients_) diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 6eff2005f8a..e6c10d15953 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -179,7 +179,7 @@ class APIServer : public Component, void on_update(update::UpdateEntity *obj) override; #endif #ifdef USE_ZWAVE_PROXY - void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg); + void on_zwave_proxy_request(const ZWaveProxyRequest &msg); #endif #ifdef USE_IR_RF void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector *timings); diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 58820ca659d..5d2c101cc4d 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -367,8 +367,8 @@ class ProtoWriteBuffer { /// Templated so concrete message type is preserved for direct encode/calculate_size calls. template void encode_message(uint32_t field_id, const T &value, bool force = true); // Non-template core for encode_message — all buffer work happens here - void encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value, - void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force); + void encode_message(uint32_t field_id, uint32_t msg_length_bytes, const void *value, + void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force); std::vector *get_buffer() const { return buffer_; } protected: @@ -936,14 +936,14 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std: // Implementation of encode_message - must be after ProtoMessage is defined template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { uint32_t msg_length_bytes = value.calculate_size(); - this->encode_message_( + this->encode_message( field_id, msg_length_bytes, &value, [](const void *msg, ProtoWriteBuffer &buf) { static_cast(msg)->encode(buf); }, force); } // Non-template core for encode_message -inline void ProtoWriteBuffer::encode_message_(uint32_t field_id, uint32_t msg_length_bytes, const void *value, - void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force) { +inline void ProtoWriteBuffer::encode_message(uint32_t field_id, uint32_t msg_length_bytes, const void *value, + void (*encode_fn)(const void *, ProtoWriteBuffer &), bool force) { if (msg_length_bytes == 0 && !force) return; this->encode_field_raw(field_id, 2); From 59b39d4388db38f1ed155b846d27627ce9458ecb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 18:35:39 -1000 Subject: [PATCH 13/42] tidy --- esphome/components/api/api_connection.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index ddf2853438b..f40f62ea9ee 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -329,12 +329,12 @@ class APIConnection final : public APIServerConnectionBase { #endif // Encode thunk — converts void* back to concrete type for direct encode() call - template static void encode_msg_(const void *msg, ProtoWriteBuffer &buffer) { + template static void encode_msg(const void *msg, ProtoWriteBuffer &buffer) { static_cast(msg)->encode(buffer); } // Size thunk — converts void* back to concrete type for direct calculate_size() call - template static uint32_t calc_size_(const void *msg) { + template static uint32_t calc_size(const void *msg) { return static_cast(msg)->calculate_size(); } From 2b80effa203e148fef9c9faae862cb42d45b58b4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 18:52:00 -1000 Subject: [PATCH 14/42] Move HAS_PROTO_MESSAGE_DUMP code from template wrappers into non-template cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduces per-instantiation cost of send_message and encode_message_to_buffer by moving the DumpBuffer/log code into send_message_() and encode_to_buffer(). The dump methods (message_name, dump_to) are still virtual on ProtoMessage, so they work correctly through the void* → ProtoMessage* cast. --- esphome/components/api/api_connection.cpp | 15 +++++++++++++++ esphome/components/api/api_connection.h | 11 ----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 4ff5ead8936..ff3a3771c9f 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1868,6 +1868,13 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { } bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + { + auto *proto_msg = static_cast(msg); + DumpBuffer dump_buf; + this->log_send_message_(proto_msg->message_name(), proto_msg->dump_to(dump_buf)); + } +#endif auto &shared_buf = this->parent_->get_shared_buffer_ref(); this->prepare_first_message_buffer(shared_buf, payload_size); size_t write_start = shared_buf.size(); @@ -1880,6 +1887,14 @@ bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, M // including header and footer overhead. Returns 0 if the message doesn't fit. uint16_t APIConnection::encode_to_buffer(uint32_t calculated_size, MessageEncodeFn encode_fn, const void *msg, APIConnection *conn, uint32_t remaining_size) { +#ifdef HAS_PROTO_MESSAGE_DUMP + if (conn->flags_.log_only_mode) { + auto *proto_msg = static_cast(msg); + DumpBuffer dump_buf; + conn->log_send_message_(proto_msg->message_name(), proto_msg->dump_to(dump_buf)); + return 1; + } +#endif // Cache frame sizes to avoid repeated virtual calls const uint8_t header_padding = conn->helper_->frame_header_padding(); const uint8_t footer_size = conn->helper_->frame_footer_size(); diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index f40f62ea9ee..7bb6b5cf6b7 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -264,10 +264,6 @@ class APIConnection final : public APIServerConnectionBase { using CalculateSizeFn = uint32_t (*)(const void *); template bool send_message(const T &msg) { -#ifdef HAS_PROTO_MESSAGE_DUMP - DumpBuffer dump_buf; - this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); -#endif if constexpr (T::ESTIMATED_SIZE == 0) { return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop, &msg); } else { @@ -350,13 +346,6 @@ class APIConnection final : public APIServerConnectionBase { // Thin template wrapper — computes size, delegates buffer work to non-template helper template static uint16_t encode_message_to_buffer(T &msg, APIConnection *conn, uint32_t remaining_size) { -#ifdef HAS_PROTO_MESSAGE_DUMP - if (conn->flags_.log_only_mode) { - DumpBuffer dump_buf; - conn->log_send_message_(msg.message_name(), msg.dump_to(dump_buf)); - return 1; - } -#endif if constexpr (T::ESTIMATED_SIZE == 0) { return encode_to_buffer(0, &encode_msg_noop, &msg, conn, remaining_size); } else { From 675db740a9dc88b325270eb202e8e05658f4f7ce Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 19:02:18 -1000 Subject: [PATCH 15/42] Replace lambda and duplicate encode_msg thunk with shared proto_encode_msg Single named free function in proto.h used by both encode_message and APIConnection send paths. Eliminates duplicate thunk definitions. --- esphome/components/api/api_connection.h | 17 ++++++----------- esphome/components/api/proto.h | 9 ++++++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 7bb6b5cf6b7..302ea75f68a 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -267,7 +267,7 @@ class APIConnection final : public APIServerConnectionBase { if constexpr (T::ESTIMATED_SIZE == 0) { return this->send_message_(0, T::MESSAGE_TYPE, &encode_msg_noop, &msg); } else { - return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &encode_msg, &msg); + return this->send_message_(msg.calculate_size(), T::MESSAGE_TYPE, &proto_encode_msg, &msg); } } @@ -324,11 +324,6 @@ class APIConnection final : public APIServerConnectionBase { void process_state_subscriptions_(); #endif - // Encode thunk — converts void* back to concrete type for direct encode() call - template static void encode_msg(const void *msg, ProtoWriteBuffer &buffer) { - static_cast(msg)->encode(buffer); - } - // Size thunk — converts void* back to concrete type for direct calculate_size() call template static uint32_t calc_size(const void *msg) { return static_cast(msg)->calculate_size(); @@ -349,7 +344,7 @@ class APIConnection final : public APIServerConnectionBase { if constexpr (T::ESTIMATED_SIZE == 0) { return encode_to_buffer(0, &encode_msg_noop, &msg, conn, remaining_size); } else { - return encode_to_buffer(msg.calculate_size(), &encode_msg, &msg, conn, remaining_size); + return encode_to_buffer(msg.calculate_size(), &proto_encode_msg, &msg, conn, remaining_size); } } @@ -362,7 +357,7 @@ class APIConnection final : public APIServerConnectionBase { template static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_state(entity, msg, &calc_size, &encode_msg, conn, remaining_size); + return fill_and_encode_entity_state(entity, msg, &calc_size, &proto_encode_msg, conn, remaining_size); } // Non-template core — fills info fields, allocates buffers, and encodes @@ -374,7 +369,7 @@ class APIConnection final : public APIServerConnectionBase { template static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_info(entity, msg, &calc_size, &encode_msg, conn, remaining_size); + return fill_and_encode_entity_info(entity, msg, &calc_size, &proto_encode_msg, conn, remaining_size); } // Non-template core — fills device_class, then delegates to fill_and_encode_entity_info @@ -388,8 +383,8 @@ class APIConnection final : public APIServerConnectionBase { 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) { - return fill_and_encode_entity_info_with_device_class(entity, msg, device_class_field, &calc_size, &encode_msg, - conn, remaining_size); + return fill_and_encode_entity_info_with_device_class(entity, msg, device_class_field, &calc_size, + &proto_encode_msg, conn, remaining_size); } #ifdef USE_VOICE_ASSISTANT diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 5d2c101cc4d..36b2fd25d9f 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -933,12 +933,15 @@ inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std: } } +// Encode thunk — converts void* back to concrete type for direct encode() call +template void proto_encode_msg(const void *msg, ProtoWriteBuffer &buf) { + static_cast(msg)->encode(buf); +} + // Implementation of encode_message - must be after ProtoMessage is defined template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { uint32_t msg_length_bytes = value.calculate_size(); - this->encode_message( - field_id, msg_length_bytes, &value, - [](const void *msg, ProtoWriteBuffer &buf) { static_cast(msg)->encode(buf); }, force); + this->encode_message(field_id, msg_length_bytes, &value, &proto_encode_msg, force); } // Non-template core for encode_message From 84070331110cf4e64d71403c4499c3205c24b97b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 19:56:31 -1000 Subject: [PATCH 16/42] dead --- esphome/components/api/proto.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 36b2fd25d9f..f630114915b 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -910,10 +910,6 @@ class ProtoSize { // Implementation of methods that depend on ProtoSize being fully defined -// Free template to calculate encoded size of any message type. -// Replaces the former virtual ProtoMessage::calculated_size() member. -template inline uint32_t calculated_size_of(const T &msg) { return msg.calculate_size(); } - // Implementation of encode_packed_sint32 - must be after ProtoSize is defined inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std::vector &values) { if (values.empty()) From e867712795a76ed1f5c43eb3b468077ce377ae35 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 19:57:53 -1000 Subject: [PATCH 17/42] tweaks --- esphome/components/api/proto.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index f630114915b..665d7dcce33 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -936,8 +936,7 @@ template void proto_encode_msg(const void *msg, ProtoWriteBuffer &bu // Implementation of encode_message - must be after ProtoMessage is defined template inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const T &value, bool force) { - uint32_t msg_length_bytes = value.calculate_size(); - this->encode_message(field_id, msg_length_bytes, &value, &proto_encode_msg, force); + this->encode_message(field_id, value.calculate_size(), &value, &proto_encode_msg, force); } // Non-template core for encode_message From 08c9990b533258da54fd42a321c54390c29e1aee Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:14:34 -1000 Subject: [PATCH 18/42] simple register --- esphome/components/api/api_pb2.cpp | 1436 ++++++++++++++------------- esphome/components/api/proto.h | 337 +------ script/api_protobuf/api_protobuf.py | 78 +- 3 files changed, 820 insertions(+), 1031 deletions(-) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index ed8c3e7bdea..a138168ca1a 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -38,12 +38,12 @@ void HelloResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(4, this->name); } uint32_t HelloResponse::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->api_version_major); - size.add_uint32(1, this->api_version_minor); - size.add_length(1, this->server_info.size()); - size.add_length(1, this->name.size()); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->api_version_major); + size += ProtoSize::uint32(1, this->api_version_minor); + size += ProtoSize::length(1, this->server_info.size()); + size += ProtoSize::length(1, this->name.size()); + return size; } #ifdef USE_AREAS void AreaInfo::encode(ProtoWriteBuffer &buffer) const { @@ -51,10 +51,10 @@ void AreaInfo::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(2, this->name); } uint32_t AreaInfo::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->area_id); - size.add_length(1, this->name.size()); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->area_id); + size += ProtoSize::length(1, this->name.size()); + return size; } #endif #ifdef USE_DEVICES @@ -64,11 +64,11 @@ void DeviceInfo::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->area_id); } uint32_t DeviceInfo::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->device_id); - size.add_length(1, this->name.size()); - size.add_uint32(1, this->area_id); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::uint32(1, this->area_id); + return size; } #endif void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { @@ -127,61 +127,61 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t DeviceInfoResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->name.size()); - size.add_length(1, this->mac_address.size()); - size.add_length(1, this->esphome_version.size()); - size.add_length(1, this->compilation_time.size()); - size.add_length(1, this->model.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::length(1, this->mac_address.size()); + size += ProtoSize::length(1, this->esphome_version.size()); + size += ProtoSize::length(1, this->compilation_time.size()); + size += ProtoSize::length(1, this->model.size()); #ifdef USE_DEEP_SLEEP - size.add_bool(1, this->has_deep_sleep); + size += ProtoSize::bool_(1, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME - size.add_length(1, this->project_name.size()); + size += ProtoSize::length(1, this->project_name.size()); #endif #ifdef ESPHOME_PROJECT_NAME - size.add_length(1, this->project_version.size()); + size += ProtoSize::length(1, this->project_version.size()); #endif #ifdef USE_WEBSERVER - size.add_uint32(1, this->webserver_port); + size += ProtoSize::uint32(1, this->webserver_port); #endif #ifdef USE_BLUETOOTH_PROXY - size.add_uint32(1, this->bluetooth_proxy_feature_flags); + size += ProtoSize::uint32(1, this->bluetooth_proxy_feature_flags); #endif - size.add_length(1, this->manufacturer.size()); - size.add_length(1, this->friendly_name.size()); + size += ProtoSize::length(1, this->manufacturer.size()); + size += ProtoSize::length(1, this->friendly_name.size()); #ifdef USE_VOICE_ASSISTANT - size.add_uint32(2, this->voice_assistant_feature_flags); + size += ProtoSize::uint32(2, this->voice_assistant_feature_flags); #endif #ifdef USE_AREAS - size.add_length(2, this->suggested_area.size()); + size += ProtoSize::length(2, this->suggested_area.size()); #endif #ifdef USE_BLUETOOTH_PROXY - size.add_length(2, this->bluetooth_mac_address.size()); + size += ProtoSize::length(2, this->bluetooth_mac_address.size()); #endif #ifdef USE_API_NOISE - size.add_bool(2, this->api_encryption_supported); + size += ProtoSize::bool_(2, this->api_encryption_supported); #endif #ifdef USE_DEVICES for (const auto &it : this->devices) { - size.add_message_object_force(2, it); + size += ProtoSize::message_force(2, it.calculate_size()); } #endif #ifdef USE_AREAS for (const auto &it : this->areas) { - size.add_message_object_force(2, it); + size += ProtoSize::message_force(2, it.calculate_size()); } #endif #ifdef USE_AREAS - size.add_message_object(2, this->area); + size += ProtoSize::message(2, this->area.calculate_size()); #endif #ifdef USE_ZWAVE_PROXY - size.add_uint32(2, this->zwave_proxy_feature_flags); + size += ProtoSize::uint32(2, this->zwave_proxy_feature_flags); #endif #ifdef USE_ZWAVE_PROXY - size.add_uint32(2, this->zwave_home_id); + size += ProtoSize::uint32(2, this->zwave_home_id); #endif - return size.get_size(); + return size; } #ifdef USE_BINARY_SENSOR void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { @@ -200,21 +200,21 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesBinarySensorResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_length(1, this->device_class.size()); - size.add_bool(1, this->is_status_binary_sensor); - size.add_bool(1, this->disabled_by_default); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->is_status_binary_sensor); + size += ProtoSize::bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -225,14 +225,14 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t BinarySensorStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->state); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } #endif #ifdef USE_COVER @@ -255,24 +255,24 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesCoverResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_bool(1, this->assumed_state); - size.add_bool(1, this->supports_position); - size.add_bool(1, this->supports_tilt); - size.add_length(1, this->device_class.size()); - size.add_bool(1, this->disabled_by_default); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::bool_(1, this->assumed_state); + size += ProtoSize::bool_(1, this->supports_position); + size += ProtoSize::bool_(1, this->supports_tilt); + size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); - size.add_bool(1, this->supports_stop); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->supports_stop); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -284,15 +284,15 @@ void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t CoverStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->position); - size.add_float(1, this->tilt); - size.add_uint32(1, static_cast(this->current_operation)); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::float_(1, this->position); + size += ProtoSize::float_(1, this->tilt); + size += ProtoSize::uint32(1, static_cast(this->current_operation)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool CoverCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -354,28 +354,28 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesFanResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_bool(1, this->supports_oscillation); - size.add_bool(1, this->supports_speed); - size.add_bool(1, this->supports_direction); - size.add_int32(1, this->supported_speed_count); - size.add_bool(1, this->disabled_by_default); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::bool_(1, this->supports_oscillation); + size += ProtoSize::bool_(1, this->supports_speed); + size += ProtoSize::bool_(1, this->supports_direction); + size += ProtoSize::int32(1, this->supported_speed_count); + size += ProtoSize::bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); if (!this->supported_preset_modes->empty()) { for (const char *it : *this->supported_preset_modes) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -389,17 +389,17 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t FanStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); - size.add_bool(1, this->oscillating); - size.add_uint32(1, static_cast(this->direction)); - size.add_int32(1, this->speed_level); - size.add_length(1, this->preset_mode.size()); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->state); + size += ProtoSize::bool_(1, this->oscillating); + size += ProtoSize::uint32(1, static_cast(this->direction)); + size += ProtoSize::int32(1, this->speed_level); + size += ProtoSize::length(1, this->preset_mode.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -485,31 +485,31 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesLightResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); if (!this->supported_color_modes->empty()) { for (const auto &it : *this->supported_color_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::uint32_force(1, static_cast(it)); } } - size.add_float(1, this->min_mireds); - size.add_float(1, this->max_mireds); + size += ProtoSize::float_(1, this->min_mireds); + size += ProtoSize::float_(1, this->max_mireds); if (!this->effects->empty()) { for (const char *it : *this->effects) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } - size.add_bool(1, this->disabled_by_default); + size += ProtoSize::bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(2, this->device_id); + size += ProtoSize::uint32(2, this->device_id); #endif - return size.get_size(); + return size; } void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -530,24 +530,24 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t LightStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); - size.add_float(1, this->brightness); - size.add_uint32(1, static_cast(this->color_mode)); - size.add_float(1, this->color_brightness); - size.add_float(1, this->red); - size.add_float(1, this->green); - size.add_float(1, this->blue); - size.add_float(1, this->white); - size.add_float(1, this->color_temperature); - size.add_float(1, this->cold_white); - size.add_float(1, this->warm_white); - size.add_length(1, this->effect.size()); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->state); + size += ProtoSize::float_(1, this->brightness); + size += ProtoSize::uint32(1, static_cast(this->color_mode)); + size += ProtoSize::float_(1, this->color_brightness); + size += ProtoSize::float_(1, this->red); + size += ProtoSize::float_(1, this->green); + size += ProtoSize::float_(1, this->blue); + size += ProtoSize::float_(1, this->white); + size += ProtoSize::float_(1, this->color_temperature); + size += ProtoSize::float_(1, this->cold_white); + size += ProtoSize::float_(1, this->warm_white); + size += ProtoSize::length(1, this->effect.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -678,24 +678,24 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesSensorResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_length(1, this->unit_of_measurement.size()); - size.add_int32(1, this->accuracy_decimals); - size.add_bool(1, this->force_update); - size.add_length(1, this->device_class.size()); - size.add_uint32(1, static_cast(this->state_class)); - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->unit_of_measurement.size()); + size += ProtoSize::int32(1, this->accuracy_decimals); + size += ProtoSize::bool_(1, this->force_update); + size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::uint32(1, static_cast(this->state_class)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -706,14 +706,14 @@ void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t SensorStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->state); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::float_(1, this->state); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } #endif #ifdef USE_SWITCH @@ -733,21 +733,21 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesSwitchResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->assumed_state); - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->assumed_state); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -757,13 +757,13 @@ void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t SwitchStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool SwitchCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -807,20 +807,20 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesTextSensorResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -831,14 +831,14 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t TextSensorStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->state.size()); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } #endif bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -859,10 +859,10 @@ void SubscribeLogsResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(3, this->message_ptr_, this->message_len_); } uint32_t SubscribeLogsResponse::calculate_size() const { - ProtoSize size; - size.add_uint32(1, static_cast(this->level)); - size.add_length(1, this->message_len_); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, static_cast(this->level)); + size += ProtoSize::length(1, this->message_len_); + return size; } #ifdef USE_API_NOISE bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -879,9 +879,9 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD } void NoiseEncryptionSetKeyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t NoiseEncryptionSetKeyResponse::calculate_size() const { - ProtoSize size; - size.add_bool(1, this->success); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::bool_(1, this->success); + return size; } #endif #ifdef USE_API_HOMEASSISTANT_SERVICES @@ -890,10 +890,10 @@ void HomeassistantServiceMap::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(2, this->value); } uint32_t HomeassistantServiceMap::calculate_size() const { - ProtoSize size; - size.add_length(1, this->key.size()); - size.add_length(1, this->value.size()); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->key.size()); + size += ProtoSize::length(1, this->value.size()); + return size; } void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->service); @@ -918,22 +918,34 @@ void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t HomeassistantActionRequest::calculate_size() const { - ProtoSize size; - size.add_length(1, this->service.size()); - size.add_repeated_message(1, this->data); - size.add_repeated_message(1, this->data_template); - size.add_repeated_message(1, this->variables); - size.add_bool(1, this->is_event); + uint32_t size = 0; + size += ProtoSize::length(1, this->service.size()); + if (!this->data.empty()) { + for (const auto &it : this->data) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + if (!this->data_template.empty()) { + for (const auto &it : this->data_template) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + if (!this->variables.empty()) { + for (const auto &it : this->variables) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + size += ProtoSize::bool_(1, this->is_event); #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES - size.add_uint32(1, this->call_id); + size += ProtoSize::uint32(1, this->call_id); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size.add_bool(1, this->wants_response); + size += ProtoSize::bool_(1, this->wants_response); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size.add_length(1, this->response_template.size()); + size += ProtoSize::length(1, this->response_template.size()); #endif - return size.get_size(); + return size; } #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES @@ -976,11 +988,11 @@ void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer &buffer) const buffer.encode_bool(3, this->once); } uint32_t SubscribeHomeAssistantStateResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->entity_id.size()); - size.add_length(1, this->attribute.size()); - size.add_bool(1, this->once); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->entity_id.size()); + size += ProtoSize::length(1, this->attribute.size()); + size += ProtoSize::bool_(1, this->once); + return size; } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -1083,10 +1095,10 @@ void ListEntitiesServicesArgument::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(2, static_cast(this->type)); } uint32_t ListEntitiesServicesArgument::calculate_size() const { - ProtoSize size; - size.add_length(1, this->name.size()); - size.add_uint32(1, static_cast(this->type)); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::uint32(1, static_cast(this->type)); + return size; } void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->name); @@ -1097,12 +1109,16 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, static_cast(this->supports_response)); } uint32_t ListEntitiesServicesResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->name.size()); - size.add_fixed32(1, this->key); - size.add_repeated_message(1, this->args); - size.add_uint32(1, static_cast(this->supports_response)); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::fixed32(1, this->key); + if (!this->args.empty()) { + for (const auto &it : this->args) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + size += ProtoSize::uint32(1, static_cast(this->supports_response)); + return size; } bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1218,14 +1234,14 @@ void ExecuteServiceResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ExecuteServiceResponse::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->call_id); - size.add_bool(1, this->success); - size.add_length(1, this->error_message.size()); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->call_id); + size += ProtoSize::bool_(1, this->success); + size += ProtoSize::length(1, this->error_message.size()); #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON - size.add_length(1, this->response_data_len); + size += ProtoSize::length(1, this->response_data_len); #endif - return size.get_size(); + return size; } #endif #ifdef USE_CAMERA @@ -1243,19 +1259,19 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesCameraResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_bool(1, this->disabled_by_default); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1266,14 +1282,14 @@ void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t CameraImageResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_length(1, this->data_len_); - size.add_bool(1, this->done); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->data_len_); + size += ProtoSize::bool_(1, this->done); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool CameraImageRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1334,61 +1350,61 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(27, this->feature_flags); } uint32_t ListEntitiesClimateResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_bool(1, this->supports_current_temperature); - size.add_bool(1, this->supports_two_point_target_temperature); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::bool_(1, this->supports_current_temperature); + size += ProtoSize::bool_(1, this->supports_two_point_target_temperature); if (!this->supported_modes->empty()) { for (const auto &it : *this->supported_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::uint32_force(1, static_cast(it)); } } - size.add_float(1, this->visual_min_temperature); - size.add_float(1, this->visual_max_temperature); - size.add_float(1, this->visual_target_temperature_step); - size.add_bool(1, this->supports_action); + size += ProtoSize::float_(1, this->visual_min_temperature); + size += ProtoSize::float_(1, this->visual_max_temperature); + size += ProtoSize::float_(1, this->visual_target_temperature_step); + size += ProtoSize::bool_(1, this->supports_action); if (!this->supported_fan_modes->empty()) { for (const auto &it : *this->supported_fan_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::uint32_force(1, static_cast(it)); } } if (!this->supported_swing_modes->empty()) { for (const auto &it : *this->supported_swing_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::uint32_force(1, static_cast(it)); } } if (!this->supported_custom_fan_modes->empty()) { for (const char *it : *this->supported_custom_fan_modes) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } if (!this->supported_presets->empty()) { for (const auto &it : *this->supported_presets) { - size.add_uint32_force(2, static_cast(it)); + size += ProtoSize::uint32_force(2, static_cast(it)); } } if (!this->supported_custom_presets->empty()) { for (const char *it : *this->supported_custom_presets) { - size.add_length_force(2, strlen(it)); + size += ProtoSize::length_force(2, strlen(it)); } } - size.add_bool(2, this->disabled_by_default); + size += ProtoSize::bool_(2, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(2, this->icon.size()); + size += ProtoSize::length(2, this->icon.size()); #endif - size.add_uint32(2, static_cast(this->entity_category)); - size.add_float(2, this->visual_current_temperature_step); - size.add_bool(2, this->supports_current_humidity); - size.add_bool(2, this->supports_target_humidity); - size.add_float(2, this->visual_min_humidity); - size.add_float(2, this->visual_max_humidity); + size += ProtoSize::uint32(2, static_cast(this->entity_category)); + size += ProtoSize::float_(2, this->visual_current_temperature_step); + size += ProtoSize::bool_(2, this->supports_current_humidity); + size += ProtoSize::bool_(2, this->supports_target_humidity); + size += ProtoSize::float_(2, this->visual_min_humidity); + size += ProtoSize::float_(2, this->visual_max_humidity); #ifdef USE_DEVICES - size.add_uint32(2, this->device_id); + size += ProtoSize::uint32(2, this->device_id); #endif - size.add_uint32(2, this->feature_flags); - return size.get_size(); + size += ProtoSize::uint32(2, this->feature_flags); + return size; } void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1410,25 +1426,25 @@ void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ClimateStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->mode)); - size.add_float(1, this->current_temperature); - size.add_float(1, this->target_temperature); - size.add_float(1, this->target_temperature_low); - size.add_float(1, this->target_temperature_high); - size.add_uint32(1, static_cast(this->action)); - size.add_uint32(1, static_cast(this->fan_mode)); - size.add_uint32(1, static_cast(this->swing_mode)); - size.add_length(1, this->custom_fan_mode.size()); - size.add_uint32(1, static_cast(this->preset)); - size.add_length(1, this->custom_preset.size()); - size.add_float(1, this->current_humidity); - size.add_float(1, this->target_humidity); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::uint32(1, static_cast(this->mode)); + size += ProtoSize::float_(1, this->current_temperature); + size += ProtoSize::float_(1, this->target_temperature); + size += ProtoSize::float_(1, this->target_temperature_low); + size += ProtoSize::float_(1, this->target_temperature_high); + size += ProtoSize::uint32(1, static_cast(this->action)); + size += ProtoSize::uint32(1, static_cast(this->fan_mode)); + size += ProtoSize::uint32(1, static_cast(this->swing_mode)); + size += ProtoSize::length(1, this->custom_fan_mode.size()); + size += ProtoSize::uint32(1, static_cast(this->preset)); + size += ProtoSize::length(1, this->custom_preset.size()); + size += ProtoSize::float_(1, this->current_humidity); + size += ProtoSize::float_(1, this->target_humidity); #ifdef USE_DEVICES - size.add_uint32(2, this->device_id); + size += ProtoSize::uint32(2, this->device_id); #endif - return size.get_size(); + return size; } bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1544,28 +1560,28 @@ void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->supported_features); } uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - size.add_float(1, this->min_temperature); - size.add_float(1, this->max_temperature); - size.add_float(1, this->target_temperature_step); + size += ProtoSize::float_(1, this->min_temperature); + size += ProtoSize::float_(1, this->max_temperature); + size += ProtoSize::float_(1, this->target_temperature_step); if (!this->supported_modes->empty()) { for (const auto &it : *this->supported_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::uint32_force(1, static_cast(it)); } } - size.add_uint32(1, this->supported_features); - return size.get_size(); + size += ProtoSize::uint32(1, this->supported_features); + return size; } void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1580,18 +1596,18 @@ void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_float(8, this->target_temperature_high); } uint32_t WaterHeaterStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->current_temperature); - size.add_float(1, this->target_temperature); - size.add_uint32(1, static_cast(this->mode)); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::float_(1, this->current_temperature); + size += ProtoSize::float_(1, this->target_temperature); + size += ProtoSize::uint32(1, static_cast(this->mode)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - size.add_uint32(1, this->state); - size.add_float(1, this->target_temperature_low); - size.add_float(1, this->target_temperature_high); - return size.get_size(); + size += ProtoSize::uint32(1, this->state); + size += ProtoSize::float_(1, this->target_temperature_low); + size += ProtoSize::float_(1, this->target_temperature_high); + return size; } bool WaterHeaterCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1655,25 +1671,25 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesNumberResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_float(1, this->min_value); - size.add_float(1, this->max_value); - size.add_float(1, this->step); - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->unit_of_measurement.size()); - size.add_uint32(1, static_cast(this->mode)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::float_(1, this->min_value); + size += ProtoSize::float_(1, this->max_value); + size += ProtoSize::float_(1, this->step); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->unit_of_measurement.size()); + size += ProtoSize::uint32(1, static_cast(this->mode)); + size += ProtoSize::length(1, this->device_class.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1684,14 +1700,14 @@ void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t NumberStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->state); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::float_(1, this->state); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool NumberCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1737,24 +1753,24 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesSelectResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif if (!this->options->empty()) { for (const char *it : *this->options) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1765,14 +1781,14 @@ void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t SelectStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->state.size()); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool SelectCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1828,26 +1844,26 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesSirenResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); + size += ProtoSize::bool_(1, this->disabled_by_default); if (!this->tones->empty()) { for (const char *it : *this->tones) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } - size.add_bool(1, this->supports_duration); - size.add_bool(1, this->supports_volume); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->supports_duration); + size += ProtoSize::bool_(1, this->supports_volume); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1857,13 +1873,13 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t SirenStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool SirenCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1939,23 +1955,23 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesLockResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_bool(1, this->assumed_state); - size.add_bool(1, this->supports_open); - size.add_bool(1, this->requires_code); - size.add_length(1, this->code_format.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->assumed_state); + size += ProtoSize::bool_(1, this->supports_open); + size += ProtoSize::bool_(1, this->requires_code); + size += ProtoSize::length(1, this->code_format.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1965,13 +1981,13 @@ void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t LockStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->state)); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2029,20 +2045,20 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesButtonResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool ButtonCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2076,13 +2092,13 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(5, this->sample_bytes); } uint32_t MediaPlayerSupportedFormat::calculate_size() const { - ProtoSize size; - size.add_length(1, this->format.size()); - size.add_uint32(1, this->sample_rate); - size.add_uint32(1, this->num_channels); - size.add_uint32(1, static_cast(this->purpose)); - size.add_uint32(1, this->sample_bytes); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->format.size()); + size += ProtoSize::uint32(1, this->sample_rate); + size += ProtoSize::uint32(1, this->num_channels); + size += ProtoSize::uint32(1, static_cast(this->purpose)); + size += ProtoSize::uint32(1, this->sample_bytes); + return size; } void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->object_id); @@ -2103,22 +2119,26 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(11, this->feature_flags); } uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_bool(1, this->supports_pause); - size.add_repeated_message(1, this->supported_formats); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->supports_pause); + if (!this->supported_formats.empty()) { + for (const auto &it : this->supported_formats) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - size.add_uint32(1, this->feature_flags); - return size.get_size(); + size += ProtoSize::uint32(1, this->feature_flags); + return size; } void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2130,15 +2150,15 @@ void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t MediaPlayerStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->state)); - size.add_float(1, this->volume); - size.add_bool(1, this->muted); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::uint32(1, static_cast(this->state)); + size += ProtoSize::float_(1, this->volume); + size += ProtoSize::bool_(1, this->muted); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2213,12 +2233,12 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(4, this->data, this->data_len); } uint32_t BluetoothLERawAdvertisement::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_sint32(1, this->rssi); - size.add_uint32(1, this->address_type); - size.add_length(1, this->data_len); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::sint32(1, this->rssi); + size += ProtoSize::uint32(1, this->address_type); + size += ProtoSize::length(1, this->data_len); + return size; } void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer &buffer) const { for (uint16_t i = 0; i < this->advertisements_len; i++) { @@ -2226,11 +2246,11 @@ void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer &buffer) cons } } uint32_t BluetoothLERawAdvertisementsResponse::calculate_size() const { - ProtoSize size; + uint32_t size = 0; for (uint16_t i = 0; i < this->advertisements_len; i++) { - size.add_message_object_force(1, this->advertisements[i]); + size += ProtoSize::message_force(1, this->advertisements[i].calculate_size()); } - return size.get_size(); + return size; } bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2258,12 +2278,12 @@ void BluetoothDeviceConnectionResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_int32(4, this->error); } uint32_t BluetoothDeviceConnectionResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_bool(1, this->connected); - size.add_uint32(1, this->mtu); - size.add_int32(1, this->error); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::bool_(1, this->connected); + size += ProtoSize::uint32(1, this->mtu); + size += ProtoSize::int32(1, this->error); + return size; } bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2284,14 +2304,14 @@ void BluetoothGATTDescriptor::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->short_uuid); } uint32_t BluetoothGATTDescriptor::calculate_size() const { - ProtoSize size; + uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size.add_uint64_force(1, this->uuid[0]); - size.add_uint64_force(1, this->uuid[1]); + size += ProtoSize::uint64_force(1, this->uuid[0]); + size += ProtoSize::uint64_force(1, this->uuid[1]); } - size.add_uint32(1, this->handle); - size.add_uint32(1, this->short_uuid); - return size.get_size(); + size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::uint32(1, this->short_uuid); + return size; } void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2306,16 +2326,20 @@ void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(5, this->short_uuid); } uint32_t BluetoothGATTCharacteristic::calculate_size() const { - ProtoSize size; + uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size.add_uint64_force(1, this->uuid[0]); - size.add_uint64_force(1, this->uuid[1]); + size += ProtoSize::uint64_force(1, this->uuid[0]); + size += ProtoSize::uint64_force(1, this->uuid[1]); } - size.add_uint32(1, this->handle); - size.add_uint32(1, this->properties); - size.add_repeated_message(1, this->descriptors); - size.add_uint32(1, this->short_uuid); - return size.get_size(); + size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::uint32(1, this->properties); + if (!this->descriptors.empty()) { + for (const auto &it : this->descriptors) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + size += ProtoSize::uint32(1, this->short_uuid); + return size; } void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2329,15 +2353,19 @@ void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->short_uuid); } uint32_t BluetoothGATTService::calculate_size() const { - ProtoSize size; + uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size.add_uint64_force(1, this->uuid[0]); - size.add_uint64_force(1, this->uuid[1]); + size += ProtoSize::uint64_force(1, this->uuid[0]); + size += ProtoSize::uint64_force(1, this->uuid[1]); } - size.add_uint32(1, this->handle); - size.add_repeated_message(1, this->characteristics); - size.add_uint32(1, this->short_uuid); - return size.get_size(); + size += ProtoSize::uint32(1, this->handle); + if (!this->characteristics.empty()) { + for (const auto &it : this->characteristics) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + size += ProtoSize::uint32(1, this->short_uuid); + return size; } void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2346,18 +2374,22 @@ void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { } } uint32_t BluetoothGATTGetServicesResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_repeated_message(1, this->services); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + if (!this->services.empty()) { + for (const auto &it : this->services) { + size += ProtoSize::message_force(1, it.calculate_size()); + } + } + return size; } void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); } uint32_t BluetoothGATTGetServicesDoneResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + return size; } bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2378,11 +2410,11 @@ void BluetoothGATTReadResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } uint32_t BluetoothGATTReadResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_length(1, this->data_len_); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::length(1, this->data_len_); + return size; } bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2472,11 +2504,11 @@ void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } uint32_t BluetoothGATTNotifyDataResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_length(1, this->data_len_); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::length(1, this->data_len_); + return size; } void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, this->free); @@ -2488,15 +2520,15 @@ void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { } } uint32_t BluetoothConnectionsFreeResponse::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->free); - size.add_uint32(1, this->limit); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->free); + size += ProtoSize::uint32(1, this->limit); for (const auto &it : this->allocated) { if (it != 0) { - size.add_uint64_force(1, it); + size += ProtoSize::uint64_force(1, it); } } - return size.get_size(); + return size; } void BluetoothGATTErrorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2504,31 +2536,31 @@ void BluetoothGATTErrorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_int32(3, this->error); } uint32_t BluetoothGATTErrorResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_int32(1, this->error); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::int32(1, this->error); + return size; } void BluetoothGATTWriteResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); } uint32_t BluetoothGATTWriteResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::uint32(1, this->handle); + return size; } void BluetoothGATTNotifyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); } uint32_t BluetoothGATTNotifyResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::uint32(1, this->handle); + return size; } void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2536,11 +2568,11 @@ void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_int32(3, this->error); } uint32_t BluetoothDevicePairingResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_bool(1, this->paired); - size.add_int32(1, this->error); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::bool_(1, this->paired); + size += ProtoSize::int32(1, this->error); + return size; } void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2548,11 +2580,11 @@ void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_int32(3, this->error); } uint32_t BluetoothDeviceUnpairingResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_bool(1, this->success); - size.add_int32(1, this->error); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::bool_(1, this->success); + size += ProtoSize::int32(1, this->error); + return size; } void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2560,11 +2592,11 @@ void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_int32(3, this->error); } uint32_t BluetoothDeviceClearCacheResponse::calculate_size() const { - ProtoSize size; - size.add_uint64(1, this->address); - size.add_bool(1, this->success); - size.add_int32(1, this->error); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint64(1, this->address); + size += ProtoSize::bool_(1, this->success); + size += ProtoSize::int32(1, this->error); + return size; } void BluetoothScannerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(1, static_cast(this->state)); @@ -2572,11 +2604,11 @@ void BluetoothScannerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, static_cast(this->configured_mode)); } uint32_t BluetoothScannerStateResponse::calculate_size() const { - ProtoSize size; - size.add_uint32(1, static_cast(this->state)); - size.add_uint32(1, static_cast(this->mode)); - size.add_uint32(1, static_cast(this->configured_mode)); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, static_cast(this->state)); + size += ProtoSize::uint32(1, static_cast(this->mode)); + size += ProtoSize::uint32(1, static_cast(this->configured_mode)); + return size; } bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2609,11 +2641,11 @@ void VoiceAssistantAudioSettings::encode(ProtoWriteBuffer &buffer) const { buffer.encode_float(3, this->volume_multiplier); } uint32_t VoiceAssistantAudioSettings::calculate_size() const { - ProtoSize size; - size.add_uint32(1, this->noise_suppression_level); - size.add_uint32(1, this->auto_gain); - size.add_float(1, this->volume_multiplier); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, this->noise_suppression_level); + size += ProtoSize::uint32(1, this->auto_gain); + size += ProtoSize::float_(1, this->volume_multiplier); + return size; } void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->start); @@ -2623,13 +2655,13 @@ void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(5, this->wake_word_phrase); } uint32_t VoiceAssistantRequest::calculate_size() const { - ProtoSize size; - size.add_bool(1, this->start); - size.add_length(1, this->conversation_id.size()); - size.add_uint32(1, this->flags); - size.add_message_object(1, this->audio_settings); - size.add_length(1, this->wake_word_phrase.size()); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::bool_(1, this->start); + size += ProtoSize::length(1, this->conversation_id.size()); + size += ProtoSize::uint32(1, this->flags); + size += ProtoSize::message(1, this->audio_settings.calculate_size()); + size += ProtoSize::length(1, this->wake_word_phrase.size()); + return size; } bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2707,10 +2739,10 @@ void VoiceAssistantAudio::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(2, this->end); } uint32_t VoiceAssistantAudio::calculate_size() const { - ProtoSize size; - size.add_length(1, this->data_len); - size.add_bool(1, this->end); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->data_len); + size += ProtoSize::bool_(1, this->end); + return size; } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2777,9 +2809,9 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength } void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t VoiceAssistantAnnounceFinished::calculate_size() const { - ProtoSize size; - size.add_bool(1, this->success); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::bool_(1, this->success); + return size; } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->id); @@ -2789,15 +2821,15 @@ void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { } } uint32_t VoiceAssistantWakeWord::calculate_size() const { - ProtoSize size; - size.add_length(1, this->id.size()); - size.add_length(1, this->wake_word.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->id.size()); + size += ProtoSize::length(1, this->wake_word.size()); if (!this->trained_languages.empty()) { for (const auto &it : this->trained_languages) { - size.add_length_force(1, it.size()); + size += ProtoSize::length_force(1, it.size()); } } - return size.get_size(); + return size; } bool VoiceAssistantExternalWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2860,15 +2892,19 @@ void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer &buffer) const buffer.encode_uint32(3, this->max_active_wake_words); } uint32_t VoiceAssistantConfigurationResponse::calculate_size() const { - ProtoSize size; - size.add_repeated_message(1, this->available_wake_words); - if (!this->active_wake_words->empty()) { - for (const auto &it : *this->active_wake_words) { - size.add_length_force(1, it.size()); + uint32_t size = 0; + if (!this->available_wake_words.empty()) { + for (const auto &it : this->available_wake_words) { + size += ProtoSize::message_force(1, it.calculate_size()); } } - size.add_uint32(1, this->max_active_wake_words); - return size.get_size(); + if (!this->active_wake_words->empty()) { + for (const auto &it : *this->active_wake_words) { + size += ProtoSize::length_force(1, it.size()); + } + } + size += ProtoSize::uint32(1, this->max_active_wake_words); + return size; } bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -2899,22 +2935,22 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) con #endif } uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_uint32(1, this->supported_features); - size.add_bool(1, this->requires_code); - size.add_bool(1, this->requires_code_to_arm); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, this->supported_features); + size += ProtoSize::bool_(1, this->requires_code); + size += ProtoSize::bool_(1, this->requires_code_to_arm); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2924,13 +2960,13 @@ void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t AlarmControlPanelStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->state)); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2988,23 +3024,23 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesTextResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_uint32(1, this->min_length); - size.add_uint32(1, this->max_length); - size.add_length(1, this->pattern.size()); - size.add_uint32(1, static_cast(this->mode)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::uint32(1, this->min_length); + size += ProtoSize::uint32(1, this->max_length); + size += ProtoSize::length(1, this->pattern.size()); + size += ProtoSize::uint32(1, static_cast(this->mode)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3015,14 +3051,14 @@ void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t TextStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->state.size()); + size += ProtoSize::bool_(1, this->missing_state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool TextCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3073,19 +3109,19 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesDateResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3098,16 +3134,16 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t DateStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->missing_state); - size.add_uint32(1, this->year); - size.add_uint32(1, this->month); - size.add_uint32(1, this->day); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::uint32(1, this->year); + size += ProtoSize::uint32(1, this->month); + size += ProtoSize::uint32(1, this->day); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool DateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3156,19 +3192,19 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesTimeResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3181,16 +3217,16 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t TimeStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->missing_state); - size.add_uint32(1, this->hour); - size.add_uint32(1, this->minute); - size.add_uint32(1, this->second); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::uint32(1, this->hour); + size += ProtoSize::uint32(1, this->minute); + size += ProtoSize::uint32(1, this->second); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool TimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3243,25 +3279,25 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesEventResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); if (!this->event_types->empty()) { for (const char *it : *this->event_types) { - size.add_length_force(1, strlen(it)); + size += ProtoSize::length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void EventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3271,13 +3307,13 @@ void EventResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t EventResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_length(1, this->event_type.size()); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->event_type.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } #endif #ifdef USE_VALVE @@ -3299,23 +3335,23 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesValveResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); - size.add_bool(1, this->assumed_state); - size.add_bool(1, this->supports_position); - size.add_bool(1, this->supports_stop); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->assumed_state); + size += ProtoSize::bool_(1, this->supports_position); + size += ProtoSize::bool_(1, this->supports_stop); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3326,14 +3362,14 @@ void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ValveStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->position); - size.add_uint32(1, static_cast(this->current_operation)); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::float_(1, this->position); + size += ProtoSize::uint32(1, static_cast(this->current_operation)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool ValveCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3382,19 +3418,19 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesDateTimeResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3405,14 +3441,14 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t DateTimeStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->missing_state); - size.add_fixed32(1, this->epoch_seconds); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::fixed32(1, this->epoch_seconds); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool DateTimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3456,20 +3492,20 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t ListEntitiesUpdateResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); - size.add_length(1, this->device_class.size()); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::length(1, this->device_class.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3487,21 +3523,21 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { #endif } uint32_t UpdateStateResponse::calculate_size() const { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_bool(1, this->missing_state); - size.add_bool(1, this->in_progress); - size.add_bool(1, this->has_progress); - size.add_float(1, this->progress); - size.add_length(1, this->current_version.size()); - size.add_length(1, this->latest_version.size()); - size.add_length(1, this->title.size()); - size.add_length(1, this->release_summary.size()); - size.add_length(1, this->release_url.size()); + uint32_t size = 0; + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::bool_(1, this->in_progress); + size += ProtoSize::bool_(1, this->has_progress); + size += ProtoSize::float_(1, this->progress); + size += ProtoSize::length(1, this->current_version.size()); + size += ProtoSize::length(1, this->latest_version.size()); + size += ProtoSize::length(1, this->title.size()); + size += ProtoSize::length(1, this->release_summary.size()); + size += ProtoSize::length(1, this->release_url.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - return size.get_size(); + return size; } bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3544,9 +3580,9 @@ bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited valu } void ZWaveProxyFrame::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(1, this->data, this->data_len); } uint32_t ZWaveProxyFrame::calculate_size() const { - ProtoSize size; - size.add_length(1, this->data_len); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::length(1, this->data_len); + return size; } bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3575,10 +3611,10 @@ void ZWaveProxyRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(2, this->data, this->data_len); } uint32_t ZWaveProxyRequest::calculate_size() const { - ProtoSize size; - size.add_uint32(1, static_cast(this->type)); - size.add_length(1, this->data_len); - return size.get_size(); + uint32_t size = 0; + size += ProtoSize::uint32(1, static_cast(this->type)); + size += ProtoSize::length(1, this->data_len); + return size; } #endif #ifdef USE_INFRARED @@ -3597,20 +3633,20 @@ void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->capabilities); } uint32_t ListEntitiesInfraredResponse::calculate_size() const { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); + uint32_t size = 0; + size += ProtoSize::length(1, this->object_id.size()); + size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::length(1, this->icon.size()); #endif - size.add_bool(1, this->disabled_by_default); - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - size.add_uint32(1, this->capabilities); - return size.get_size(); + size += ProtoSize::uint32(1, this->capabilities); + return size; } #endif #ifdef USE_IR_RF @@ -3665,17 +3701,17 @@ void InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer) const { } } uint32_t InfraredRFReceiveEvent::calculate_size() const { - ProtoSize size; + uint32_t size = 0; #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::uint32(1, this->device_id); #endif - size.add_fixed32(1, this->key); + size += ProtoSize::fixed32(1, this->key); if (!this->timings->empty()) { for (const auto &it : *this->timings) { - size.add_sint32_force(1, it); + size += ProtoSize::sint32_force(1, it); } } - return size.get_size(); + return size; } #endif diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 665d7dcce33..410e604b99f 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -497,32 +497,7 @@ class ProtoDecodableMessage : public ProtoMessage { }; class ProtoSize { - private: - uint32_t total_size_ = 0; - public: - /** - * @brief ProtoSize class for Protocol Buffer serialization size calculation - * - * This class provides methods to calculate the exact byte counts needed - * for encoding various Protocol Buffer field types. The class now uses an - * object-based approach to reduce parameter passing overhead while keeping - * varint calculation methods static for external use. - * - * Implements Protocol Buffer encoding size calculation according to: - * https://protobuf.dev/programming-guides/encoding/ - * - * Key features: - * - Object-based approach reduces flash usage by eliminating parameter passing - * - Early-return optimization for zero/default values - * - Static varint methods for external callers - * - Specialized handling for different field types according to protobuf spec - */ - - ProtoSize() = default; - - uint32_t get_size() const { return total_size_; } - /** * @brief Calculates the size in bytes needed to encode a uint32_t value as a varint * @@ -619,292 +594,62 @@ class ProtoSize { return varint(tag); } - /** - * @brief Common parameters for all add_*_field methods - * - * All add_*_field methods follow these common patterns: - * * @param field_id_size Pre-calculated size of the field ID in bytes - * @param value The value to calculate size for (type varies) - * @param force Whether to calculate size even if the value is default/zero/empty - * - * Each method follows this implementation pattern: - * 1. Skip calculation if value is default (0, false, empty) and not forced - * 2. Calculate the size based on the field's encoding rules - * 3. Add the field_id_size + calculated value size to total_size - */ - - /** - * @brief Calculates and adds the size of an int32 field to the total message size - */ - inline void add_int32(uint32_t field_id_size, int32_t value) { - if (value != 0) { - add_int32_force(field_id_size, value); - } + // Static methods that RETURN size contribution (no ProtoSize object needed). + // Used by generated calculate_size() methods to accumulate into a plain uint32_t register. + static constexpr uint32_t int32(uint32_t field_id_size, int32_t value) { + return value ? field_id_size + (value < 0 ? 10 : varint(static_cast(value))) : 0; } - - /** - * @brief Calculates and adds the size of an int32 field to the total message size (force version) - */ - inline void add_int32_force(uint32_t field_id_size, int32_t value) { - // Always calculate size when forced - // Negative values are encoded as 10-byte varints in protobuf - total_size_ += field_id_size + (value < 0 ? 10 : varint(static_cast(value))); + static constexpr uint32_t int32_force(uint32_t field_id_size, int32_t value) { + return field_id_size + (value < 0 ? 10 : varint(static_cast(value))); } - - /** - * @brief Calculates and adds the size of a uint32 field to the total message size - */ - inline void add_uint32(uint32_t field_id_size, uint32_t value) { - if (value != 0) { - add_uint32_force(field_id_size, value); - } + static constexpr uint32_t uint32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + varint(value) : 0; } - - /** - * @brief Calculates and adds the size of a uint32 field to the total message size (force version) - */ - inline void add_uint32_force(uint32_t field_id_size, uint32_t value) { - // Always calculate size when force is true - total_size_ += field_id_size + varint(value); + static constexpr uint32_t uint32_force(uint32_t field_id_size, uint32_t value) { + return field_id_size + varint(value); } - - /** - * @brief Calculates and adds the size of a boolean field to the total message size - */ - inline void add_bool(uint32_t field_id_size, bool value) { - if (value) { - // Boolean fields always use 1 byte when true - total_size_ += field_id_size + 1; - } + static constexpr uint32_t bool_(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } + static constexpr uint32_t bool_force(uint32_t field_id_size) { return field_id_size + 1; } + static constexpr uint32_t float_(uint32_t field_id_size, float value) { + return value != 0.0f ? field_id_size + 4 : 0; } - - /** - * @brief Calculates and adds the size of a boolean field to the total message size (force version) - */ - inline void add_bool_force(uint32_t field_id_size, bool value) { - // Always calculate size when force is true - // Boolean fields always use 1 byte - total_size_ += field_id_size + 1; + static constexpr uint32_t fixed32(uint32_t field_id_size, uint32_t value) { return value ? field_id_size + 4 : 0; } + static constexpr uint32_t sfixed32(uint32_t field_id_size, int32_t value) { return value ? field_id_size + 4 : 0; } + static constexpr uint32_t sint32(uint32_t field_id_size, int32_t value) { + return value ? field_id_size + varint(encode_zigzag32(value)) : 0; } - - /** - * @brief Calculates and adds the size of a float field to the total message size - */ - inline void add_float(uint32_t field_id_size, float value) { - if (value != 0.0f) { - total_size_ += field_id_size + 4; - } + static constexpr uint32_t sint32_force(uint32_t field_id_size, int32_t value) { + return field_id_size + varint(encode_zigzag32(value)); } - - // NOTE: add_double_field removed - wire type 1 (64-bit: double) not supported - // to reduce overhead on embedded systems - - /** - * @brief Calculates and adds the size of a fixed32 field to the total message size - */ - inline void add_fixed32(uint32_t field_id_size, uint32_t value) { - if (value != 0) { - total_size_ += field_id_size + 4; - } + static constexpr uint32_t int64(uint32_t field_id_size, int64_t value) { + return value ? field_id_size + varint(value) : 0; } - - // NOTE: add_fixed64_field removed - wire type 1 (64-bit: fixed64) not supported - // to reduce overhead on embedded systems - - /** - * @brief Calculates and adds the size of a sfixed32 field to the total message size - */ - inline void add_sfixed32(uint32_t field_id_size, int32_t value) { - if (value != 0) { - total_size_ += field_id_size + 4; - } + static constexpr uint32_t int64_force(uint32_t field_id_size, int64_t value) { return field_id_size + varint(value); } + static constexpr uint32_t uint64(uint32_t field_id_size, uint64_t value) { + return value ? field_id_size + varint(value) : 0; } - - // NOTE: add_sfixed64_field removed - wire type 1 (64-bit: sfixed64) not supported - // to reduce overhead on embedded systems - - /** - * @brief Calculates and adds the size of a sint32 field to the total message size - * - * Sint32 fields use ZigZag encoding, which is more efficient for negative values. - */ - inline void add_sint32(uint32_t field_id_size, int32_t value) { - if (value != 0) { - add_sint32_force(field_id_size, value); - } + static constexpr uint32_t uint64_force(uint32_t field_id_size, uint64_t value) { + return field_id_size + varint(value); } - - /** - * @brief Calculates and adds the size of a sint32 field to the total message size (force version) - * - * Sint32 fields use ZigZag encoding, which is more efficient for negative values. - */ - inline void add_sint32_force(uint32_t field_id_size, int32_t value) { - // Always calculate size when force is true - // ZigZag encoding for sint32 - total_size_ += field_id_size + varint(encode_zigzag32(value)); + static constexpr uint32_t length(uint32_t field_id_size, size_t len) { + return len ? field_id_size + varint(static_cast(len)) + static_cast(len) : 0; } - - /** - * @brief Calculates and adds the size of an int64 field to the total message size - */ - inline void add_int64(uint32_t field_id_size, int64_t value) { - if (value != 0) { - add_int64_force(field_id_size, value); - } + static constexpr uint32_t length_force(uint32_t field_id_size, size_t len) { + return field_id_size + varint(static_cast(len)) + static_cast(len); } - - /** - * @brief Calculates and adds the size of an int64 field to the total message size (force version) - */ - inline void add_int64_force(uint32_t field_id_size, int64_t value) { - // Always calculate size when force is true - total_size_ += field_id_size + varint(value); + static constexpr uint32_t sint64(uint32_t field_id_size, int64_t value) { + return value ? field_id_size + varint(encode_zigzag64(value)) : 0; } - - /** - * @brief Calculates and adds the size of a uint64 field to the total message size - */ - inline void add_uint64(uint32_t field_id_size, uint64_t value) { - if (value != 0) { - add_uint64_force(field_id_size, value); - } + static constexpr uint32_t sint64_force(uint32_t field_id_size, int64_t value) { + return field_id_size + varint(encode_zigzag64(value)); } - - /** - * @brief Calculates and adds the size of a uint64 field to the total message size (force version) - */ - inline void add_uint64_force(uint32_t field_id_size, uint64_t value) { - // Always calculate size when force is true - total_size_ += field_id_size + varint(value); + static constexpr uint32_t fixed64(uint32_t field_id_size, uint64_t value) { return value ? field_id_size + 8 : 0; } + static constexpr uint32_t sfixed64(uint32_t field_id_size, int64_t value) { return value ? field_id_size + 8 : 0; } + static constexpr uint32_t message(uint32_t field_id_size, uint32_t nested_size) { + return nested_size ? field_id_size + varint(nested_size) + nested_size : 0; } - - // NOTE: sint64 support functions (add_sint64_field, add_sint64_field_force) removed - // sint64 type is not supported by ESPHome API to reduce overhead on embedded systems - - /** - * @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size - */ - inline void add_length(uint32_t field_id_size, size_t len) { - if (len != 0) { - add_length_force(field_id_size, len); - } - } - - /** - * @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size (repeated - * field version) - */ - inline void add_length_force(uint32_t field_id_size, size_t len) { - // Always calculate size when force is true - // Field ID + length varint + data bytes - total_size_ += field_id_size + varint(static_cast(len)) + static_cast(len); - } - - /** - * @brief Adds a pre-calculated size directly to the total - * - * This is used when we can calculate the total size by multiplying the number - * of elements by the bytes per element (for repeated fixed-size types like float, fixed32, etc.) - * - * @param size The pre-calculated total size to add - */ - inline void add_precalculated_size(uint32_t size) { total_size_ += size; } - - /** - * @brief Calculates and adds the size of a nested message field to the total message size - * - * This helper function directly updates the total_size reference if the nested size - * is greater than zero. - * - * @param nested_size The pre-calculated size of the nested message - */ - inline void add_message_field(uint32_t field_id_size, uint32_t nested_size) { - if (nested_size != 0) { - add_message_field_force(field_id_size, nested_size); - } - } - - /** - * @brief Calculates and adds the size of a nested message field to the total message size (force version) - * - * @param nested_size The pre-calculated size of the nested message - */ - inline void add_message_field_force(uint32_t field_id_size, uint32_t nested_size) { - // Always calculate size when force is true - // Field ID + length varint + nested message content - total_size_ += field_id_size + varint(nested_size) + nested_size; - } - - /** - * @brief Calculates and adds the size of a nested message field to the total message size - * - * This version takes a ProtoMessage object, calculates its size internally, - * and updates the total_size reference. This eliminates the need for a temporary variable - * at the call site. - * - * @param message The nested message object - */ - template inline void add_message_object(uint32_t field_id_size, const T &message) { - add_message_field(field_id_size, message.calculate_size()); - } - - template inline void add_message_object_force(uint32_t field_id_size, const T &message) { - add_message_field_force(field_id_size, message.calculate_size()); - } - - /** - * @brief Calculates and adds the sizes of all messages in a repeated field to the total message size - * - * This helper processes a vector of message objects, calculating the size for each message - * and adding it to the total size. - * - * @tparam MessageType The type of the nested messages in the vector - * @param messages Vector of message objects - */ - template - inline void add_repeated_message(uint32_t field_id_size, const std::vector &messages) { - // Skip if the vector is empty - if (!messages.empty()) { - // Use the force version for all messages in the repeated field - for (const auto &message : messages) { - add_message_object_force(field_id_size, message); - } - } - } - - /** - * @brief Calculates and adds the sizes of all messages in a repeated field to the total message size (FixedVector - * version) - * - * @tparam MessageType The type of the nested messages in the FixedVector - * @param messages FixedVector of message objects - */ - template - inline void add_repeated_message(uint32_t field_id_size, const FixedVector &messages) { - // Skip if the fixed vector is empty - if (!messages.empty()) { - // Use the force version for all messages in the repeated field - for (const auto &message : messages) { - add_message_object_force(field_id_size, message); - } - } - } - - /** - * @brief Calculate size of a packed repeated sint32 field - */ - inline void add_packed_sint32(uint32_t field_id_size, const std::vector &values) { - if (values.empty()) - return; - - size_t packed_size = 0; - for (int value : values) { - packed_size += varint(encode_zigzag32(value)); - } - - // field_id + length varint + packed data - total_size_ += field_id_size + varint(static_cast(packed_size)) + static_cast(packed_size); + static constexpr uint32_t message_force(uint32_t field_id_size, uint32_t nested_size) { + return field_id_size + varint(nested_size) + nested_size; } }; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 9906982c7f5..e5106c85001 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -270,18 +270,18 @@ class TypeInfo(ABC): def _get_simple_size_calculation( self, name: str, force: bool, base_method: str, value_expr: str = None ) -> str: - """Helper for simple size calculations. + """Helper for simple size calculations using static ProtoSize methods. Args: name: Field name force: Whether this is for a repeated field - base_method: Base method name (e.g., "add_int32") + base_method: Base method name (e.g., "int32") value_expr: Optional value expression (defaults to name) """ field_id_size = self.calculate_field_id_size() method = f"{base_method}_force" if force else base_method value = value_expr or name - return f"size.{method}({field_id_size}, {value});" + return f"size += ProtoSize::{method}({field_id_size}, {value});" @abstractmethod def get_size_calculation(self, name: str, force: bool = False) -> str: @@ -410,7 +410,7 @@ class DoubleType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_double({field_id_size}, {name});" + return f"size += ProtoSize::fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -434,7 +434,7 @@ class FloatType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_float({field_id_size}, {name});" + return f"size += ProtoSize::float_({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -457,7 +457,7 @@ class Int64Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_int64") + return self._get_simple_size_calculation(name, force, "int64") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -477,7 +477,7 @@ class UInt64Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_uint64") + return self._get_simple_size_calculation(name, force, "uint64") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -497,7 +497,7 @@ class Int32Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_int32") + return self._get_simple_size_calculation(name, force, "int32") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -518,7 +518,7 @@ class Fixed64Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_fixed64({field_id_size}, {name});" + return f"size += ProtoSize::fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -542,7 +542,7 @@ class Fixed32Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_fixed32({field_id_size}, {name});" + return f"size += ProtoSize::fixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -563,7 +563,7 @@ class BoolType(TypeInfo): return f"out.append(YESNO({name}));" def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_bool") + return self._get_simple_size_calculation(name, force, "bool_") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 1 # field ID + 1 byte @@ -647,18 +647,18 @@ class StringType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: # For SOURCE_CLIENT only messages, use the string field directly if not self._needs_encode: - return self._get_simple_size_calculation(name, force, "add_length") + return self._get_simple_size_calculation(name, force, "length") # Check if this is being called from a repeated field context # In that case, 'name' will be 'it' and we need to use the repeated version if name == "it": - # For repeated fields, we need to use add_length_force which includes field ID + # For repeated fields, we need to use length_force which includes field ID field_id_size = self.calculate_field_id_size() - return f"size.add_length_force({field_id_size}, it.size());" + return f"size += ProtoSize::length_force({field_id_size}, it.size());" # For messages that need encoding, use the StringRef size field_id_size = self.calculate_field_id_size() - return f"size.add_length({field_id_size}, this->{self.field_name}_ref_.size());" + return f"size += ProtoSize::length({field_id_size}, this->{self.field_name}_ref_.size());" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string @@ -721,7 +721,9 @@ class MessageType(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_message_object") + field_id_size = self.calculate_field_id_size() + method = "message_force" if force else "message" + return f"size += ProtoSize::{method}({field_id_size}, {name}.calculate_size());" def get_estimated_size(self) -> int: # For message types, we can't easily estimate the submessage size without @@ -822,7 +824,7 @@ class BytesType(TypeInfo): ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size.add_length({self.calculate_field_id_size()}, this->{self.field_name}_len_);" + return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}_len_);" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical bytes @@ -897,7 +899,7 @@ class PointerToBytesBufferType(PointerToBufferTypeBase): ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size.add_length({self.calculate_field_id_size()}, this->{self.field_name}_len);" + return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}_len);" class PointerToStringBufferType(PointerToBufferTypeBase): @@ -939,7 +941,7 @@ class PointerToStringBufferType(PointerToBufferTypeBase): return f'dump_field(out, "{self.name}", this->{self.field_name});' def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size.add_length({self.calculate_field_id_size()}, this->{self.field_name}.size());" + return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}.size());" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string @@ -1103,9 +1105,9 @@ class FixedArrayBytesType(TypeInfo): if force: # For repeated fields, always calculate size (no zero check) - return f"size.add_length_force({field_id_size}, {length_field});" - # For non-repeated fields, add_length already checks for zero - return f"size.add_length({field_id_size}, {length_field});" + return f"size += ProtoSize::length_force({field_id_size}, {length_field});" + # For non-repeated fields, length already checks for zero + return f"size += ProtoSize::length({field_id_size}, {length_field});" def get_estimated_size(self) -> int: # Estimate based on typical BLE advertisement size @@ -1132,7 +1134,7 @@ class UInt32Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_uint32") + return self._get_simple_size_calculation(name, force, "uint32") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -1168,7 +1170,7 @@ class EnumType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: return self._get_simple_size_calculation( - name, force, "add_uint32", f"static_cast({name})" + name, force, "uint32", f"static_cast({name})" ) def get_estimated_size(self) -> int: @@ -1190,7 +1192,7 @@ class SFixed32Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_sfixed32({field_id_size}, {name});" + return f"size += ProtoSize::sfixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -1214,7 +1216,7 @@ class SFixed64Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size.add_sfixed64({field_id_size}, {name});" + return f"size += ProtoSize::sfixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -1237,7 +1239,7 @@ class SInt32Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_sint32") + return self._get_simple_size_calculation(name, force, "sint32") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -1257,7 +1259,7 @@ class SInt64Type(TypeInfo): return o def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_sint64") + return self._get_simple_size_calculation(name, force, "sint64") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint @@ -1694,11 +1696,17 @@ class RepeatedTypeInfo(TypeInfo): # For repeated fields, we always need to pass force=True to the underlying type's calculation # This is because the encode method always sets force=true for repeated fields - # Handle message types separately as they use a dedicated helper + # Handle message types separately - generate inline loop if isinstance(self._ti, MessageType): field_id_size = self._ti.calculate_field_id_size() - container = f"*{name}" if self._use_pointer else name - return f"size.add_repeated_message({field_id_size}, {container});" + container_ref = f"*{name}" if self._use_pointer else name + empty_check = f"{name}->empty()" if self._use_pointer else f"{name}.empty()" + o = f"if (!{empty_check}) {{\n" + o += f" for (const auto &it : {container_ref}) {{\n" + o += f" size += ProtoSize::message_force({field_id_size}, it.calculate_size());\n" + o += " }\n" + o += "}" + return o # For non-message types, generate size calculation with iteration container_ref = f"*{name}" if self._use_pointer else name @@ -1713,14 +1721,14 @@ class RepeatedTypeInfo(TypeInfo): field_id_size = self._ti.calculate_field_id_size() bytes_per_element = field_id_size + num_bytes size_expr = f"{name}->size()" if self._use_pointer else f"{name}.size()" - o += f" size.add_precalculated_size({size_expr} * {bytes_per_element});\n" + o += f" size += {size_expr} * {bytes_per_element};\n" else: # Other types need the actual value # Special handling for const char* elements if self._use_pointer and "const char" in self._container_no_template: field_id_size = self.calculate_field_id_size() o += f" for (const char *it : {container_ref}) {{\n" - o += f" size.add_length_force({field_id_size}, strlen(it));\n" + o += f" size += ProtoSize::length_force({field_id_size}, strlen(it));\n" else: auto_ref = "" if self._ti_is_bool else "&" o += f" for (const auto {auto_ref}it : {container_ref}) {{\n" @@ -2240,9 +2248,9 @@ def build_message_type( # Add calculate_size method only if this message needs encoding and has fields if needs_encode and size_calc: o = f"uint32_t {desc.name}::calculate_size() const {{\n" - o += " ProtoSize size;\n" + o += " uint32_t size = 0;\n" o += indent("\n".join(size_calc)) + "\n" - o += " return size.get_size();\n" + o += " return size;\n" o += "}\n" cpp += o prot = "uint32_t calculate_size() const;" From daf2e6ecc8eb0af5b1245eac26aff3e7599876ce Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:21:25 -1000 Subject: [PATCH 19/42] naming --- esphome/components/api/api_pb2.cpp | 1044 +++++++++++++-------------- esphome/components/api/proto.h | 60 +- script/api_protobuf/api_protobuf.py | 34 +- 3 files changed, 574 insertions(+), 564 deletions(-) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index a138168ca1a..d60ef1acd0e 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -39,10 +39,10 @@ void HelloResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t HelloResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->api_version_major); - size += ProtoSize::uint32(1, this->api_version_minor); - size += ProtoSize::length(1, this->server_info.size()); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_uint32(1, this->api_version_major); + size += ProtoSize::calc_uint32(1, this->api_version_minor); + size += ProtoSize::calc_length(1, this->server_info.size()); + size += ProtoSize::calc_length(1, this->name.size()); return size; } #ifdef USE_AREAS @@ -52,8 +52,8 @@ void AreaInfo::encode(ProtoWriteBuffer &buffer) const { } uint32_t AreaInfo::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->area_id); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_uint32(1, this->area_id); + size += ProtoSize::calc_length(1, this->name.size()); return size; } #endif @@ -65,9 +65,9 @@ void DeviceInfo::encode(ProtoWriteBuffer &buffer) const { } uint32_t DeviceInfo::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->device_id); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::uint32(1, this->area_id); + size += ProtoSize::calc_uint32(1, this->device_id); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_uint32(1, this->area_id); return size; } #endif @@ -128,58 +128,58 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t DeviceInfoResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::length(1, this->mac_address.size()); - size += ProtoSize::length(1, this->esphome_version.size()); - size += ProtoSize::length(1, this->compilation_time.size()); - size += ProtoSize::length(1, this->model.size()); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->mac_address.size()); + size += ProtoSize::calc_length(1, this->esphome_version.size()); + size += ProtoSize::calc_length(1, this->compilation_time.size()); + size += ProtoSize::calc_length(1, this->model.size()); #ifdef USE_DEEP_SLEEP - size += ProtoSize::bool_(1, this->has_deep_sleep); + size += ProtoSize::calc_bool_(1, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME - size += ProtoSize::length(1, this->project_name.size()); + size += ProtoSize::calc_length(1, this->project_name.size()); #endif #ifdef ESPHOME_PROJECT_NAME - size += ProtoSize::length(1, this->project_version.size()); + size += ProtoSize::calc_length(1, this->project_version.size()); #endif #ifdef USE_WEBSERVER - size += ProtoSize::uint32(1, this->webserver_port); + size += ProtoSize::calc_uint32(1, this->webserver_port); #endif #ifdef USE_BLUETOOTH_PROXY - size += ProtoSize::uint32(1, this->bluetooth_proxy_feature_flags); + size += ProtoSize::calc_uint32(1, this->bluetooth_proxy_feature_flags); #endif - size += ProtoSize::length(1, this->manufacturer.size()); - size += ProtoSize::length(1, this->friendly_name.size()); + size += ProtoSize::calc_length(1, this->manufacturer.size()); + size += ProtoSize::calc_length(1, this->friendly_name.size()); #ifdef USE_VOICE_ASSISTANT - size += ProtoSize::uint32(2, this->voice_assistant_feature_flags); + size += ProtoSize::calc_uint32(2, this->voice_assistant_feature_flags); #endif #ifdef USE_AREAS - size += ProtoSize::length(2, this->suggested_area.size()); + size += ProtoSize::calc_length(2, this->suggested_area.size()); #endif #ifdef USE_BLUETOOTH_PROXY - size += ProtoSize::length(2, this->bluetooth_mac_address.size()); + size += ProtoSize::calc_length(2, this->bluetooth_mac_address.size()); #endif #ifdef USE_API_NOISE - size += ProtoSize::bool_(2, this->api_encryption_supported); + size += ProtoSize::calc_bool_(2, this->api_encryption_supported); #endif #ifdef USE_DEVICES for (const auto &it : this->devices) { - size += ProtoSize::message_force(2, it.calculate_size()); + size += ProtoSize::calc_message_force(2, it.calculate_size()); } #endif #ifdef USE_AREAS for (const auto &it : this->areas) { - size += ProtoSize::message_force(2, it.calculate_size()); + size += ProtoSize::calc_message_force(2, it.calculate_size()); } #endif #ifdef USE_AREAS - size += ProtoSize::message(2, this->area.calculate_size()); + size += ProtoSize::calc_message(2, this->area.calculate_size()); #endif #ifdef USE_ZWAVE_PROXY - size += ProtoSize::uint32(2, this->zwave_proxy_feature_flags); + size += ProtoSize::calc_uint32(2, this->zwave_proxy_feature_flags); #endif #ifdef USE_ZWAVE_PROXY - size += ProtoSize::uint32(2, this->zwave_home_id); + size += ProtoSize::calc_uint32(2, this->zwave_home_id); #endif return size; } @@ -201,18 +201,18 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesBinarySensorResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::length(1, this->device_class.size()); - size += ProtoSize::bool_(1, this->is_status_binary_sensor); - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->is_status_binary_sensor); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -226,11 +226,11 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BinarySensorStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->state); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -256,21 +256,21 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesCoverResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::bool_(1, this->assumed_state); - size += ProtoSize::bool_(1, this->supports_position); - size += ProtoSize::bool_(1, this->supports_tilt); - size += ProtoSize::length(1, this->device_class.size()); - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_bool_(1, this->assumed_state); + size += ProtoSize::calc_bool_(1, this->supports_position); + size += ProtoSize::calc_bool_(1, this->supports_tilt); + size += ProtoSize::calc_length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::bool_(1, this->supports_stop); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->supports_stop); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -285,12 +285,12 @@ void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t CoverStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::float_(1, this->position); - size += ProtoSize::float_(1, this->tilt); - size += ProtoSize::uint32(1, static_cast(this->current_operation)); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->position); + size += ProtoSize::calc_float(1, this->tilt); + size += ProtoSize::calc_uint32(1, static_cast(this->current_operation)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -355,25 +355,25 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesFanResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::bool_(1, this->supports_oscillation); - size += ProtoSize::bool_(1, this->supports_speed); - size += ProtoSize::bool_(1, this->supports_direction); - size += ProtoSize::int32(1, this->supported_speed_count); - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_bool_(1, this->supports_oscillation); + size += ProtoSize::calc_bool_(1, this->supports_speed); + size += ProtoSize::calc_bool_(1, this->supports_direction); + size += ProtoSize::calc_int32(1, this->supported_speed_count); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); if (!this->supported_preset_modes->empty()) { for (const char *it : *this->supported_preset_modes) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -390,14 +390,14 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t FanStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->state); - size += ProtoSize::bool_(1, this->oscillating); - size += ProtoSize::uint32(1, static_cast(this->direction)); - size += ProtoSize::int32(1, this->speed_level); - size += ProtoSize::length(1, this->preset_mode.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_bool_(1, this->oscillating); + size += ProtoSize::calc_uint32(1, static_cast(this->direction)); + size += ProtoSize::calc_int32(1, this->speed_level); + size += ProtoSize::calc_length(1, this->preset_mode.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -486,28 +486,28 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesLightResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); if (!this->supported_color_modes->empty()) { for (const auto &it : *this->supported_color_modes) { - size += ProtoSize::uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } - size += ProtoSize::float_(1, this->min_mireds); - size += ProtoSize::float_(1, this->max_mireds); + size += ProtoSize::calc_float(1, this->min_mireds); + size += ProtoSize::calc_float(1, this->max_mireds); if (!this->effects->empty()) { for (const char *it : *this->effects) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif return size; } @@ -531,21 +531,21 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t LightStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->state); - size += ProtoSize::float_(1, this->brightness); - size += ProtoSize::uint32(1, static_cast(this->color_mode)); - size += ProtoSize::float_(1, this->color_brightness); - size += ProtoSize::float_(1, this->red); - size += ProtoSize::float_(1, this->green); - size += ProtoSize::float_(1, this->blue); - size += ProtoSize::float_(1, this->white); - size += ProtoSize::float_(1, this->color_temperature); - size += ProtoSize::float_(1, this->cold_white); - size += ProtoSize::float_(1, this->warm_white); - size += ProtoSize::length(1, this->effect.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_float(1, this->brightness); + size += ProtoSize::calc_uint32(1, static_cast(this->color_mode)); + size += ProtoSize::calc_float(1, this->color_brightness); + size += ProtoSize::calc_float(1, this->red); + size += ProtoSize::calc_float(1, this->green); + size += ProtoSize::calc_float(1, this->blue); + size += ProtoSize::calc_float(1, this->white); + size += ProtoSize::calc_float(1, this->color_temperature); + size += ProtoSize::calc_float(1, this->cold_white); + size += ProtoSize::calc_float(1, this->warm_white); + size += ProtoSize::calc_length(1, this->effect.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -679,21 +679,21 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesSensorResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::length(1, this->unit_of_measurement.size()); - size += ProtoSize::int32(1, this->accuracy_decimals); - size += ProtoSize::bool_(1, this->force_update); - size += ProtoSize::length(1, this->device_class.size()); - size += ProtoSize::uint32(1, static_cast(this->state_class)); - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); + size += ProtoSize::calc_int32(1, this->accuracy_decimals); + size += ProtoSize::calc_bool_(1, this->force_update); + size += ProtoSize::calc_length(1, this->device_class.size()); + size += ProtoSize::calc_uint32(1, static_cast(this->state_class)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -707,11 +707,11 @@ void SensorStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t SensorStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::float_(1, this->state); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->state); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -734,18 +734,18 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesSwitchResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->assumed_state); - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->assumed_state); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -758,10 +758,10 @@ void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t SwitchStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -808,17 +808,17 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesTextSensorResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -832,11 +832,11 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t TextSensorStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->state.size()); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->state.size()); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -860,8 +860,8 @@ void SubscribeLogsResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t SubscribeLogsResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, static_cast(this->level)); - size += ProtoSize::length(1, this->message_len_); + size += ProtoSize::calc_uint32(1, static_cast(this->level)); + size += ProtoSize::calc_length(1, this->message_len_); return size; } #ifdef USE_API_NOISE @@ -880,7 +880,7 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD void NoiseEncryptionSetKeyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t NoiseEncryptionSetKeyResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::bool_(1, this->success); + size += ProtoSize::calc_bool_(1, this->success); return size; } #endif @@ -891,8 +891,8 @@ void HomeassistantServiceMap::encode(ProtoWriteBuffer &buffer) const { } uint32_t HomeassistantServiceMap::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->key.size()); - size += ProtoSize::length(1, this->value.size()); + size += ProtoSize::calc_length(1, this->key.size()); + size += ProtoSize::calc_length(1, this->value.size()); return size; } void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { @@ -919,31 +919,31 @@ void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { } uint32_t HomeassistantActionRequest::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->service.size()); + size += ProtoSize::calc_length(1, this->service.size()); if (!this->data.empty()) { for (const auto &it : this->data) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } if (!this->data_template.empty()) { for (const auto &it : this->data_template) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } if (!this->variables.empty()) { for (const auto &it : this->variables) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size += ProtoSize::bool_(1, this->is_event); + size += ProtoSize::calc_bool_(1, this->is_event); #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES - size += ProtoSize::uint32(1, this->call_id); + size += ProtoSize::calc_uint32(1, this->call_id); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size += ProtoSize::bool_(1, this->wants_response); + size += ProtoSize::calc_bool_(1, this->wants_response); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size += ProtoSize::length(1, this->response_template.size()); + size += ProtoSize::calc_length(1, this->response_template.size()); #endif return size; } @@ -989,9 +989,9 @@ void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer &buffer) const } uint32_t SubscribeHomeAssistantStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->entity_id.size()); - size += ProtoSize::length(1, this->attribute.size()); - size += ProtoSize::bool_(1, this->once); + size += ProtoSize::calc_length(1, this->entity_id.size()); + size += ProtoSize::calc_length(1, this->attribute.size()); + size += ProtoSize::calc_bool_(1, this->once); return size; } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -1096,8 +1096,8 @@ void ListEntitiesServicesArgument::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesServicesArgument::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::uint32(1, static_cast(this->type)); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_uint32(1, static_cast(this->type)); return size; } void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { @@ -1110,14 +1110,14 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesServicesResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_fixed32(1, this->key); if (!this->args.empty()) { for (const auto &it : this->args) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size += ProtoSize::uint32(1, static_cast(this->supports_response)); + size += ProtoSize::calc_uint32(1, static_cast(this->supports_response)); return size; } bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -1235,11 +1235,11 @@ void ExecuteServiceResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ExecuteServiceResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->call_id); - size += ProtoSize::bool_(1, this->success); - size += ProtoSize::length(1, this->error_message.size()); + size += ProtoSize::calc_uint32(1, this->call_id); + size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_length(1, this->error_message.size()); #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON - size += ProtoSize::length(1, this->response_data_len); + size += ProtoSize::calc_length(1, this->response_data_len); #endif return size; } @@ -1260,16 +1260,16 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesCameraResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1283,11 +1283,11 @@ void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t CameraImageResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->data_len_); - size += ProtoSize::bool_(1, this->done); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->data_len_); + size += ProtoSize::calc_bool_(1, this->done); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1351,59 +1351,59 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesClimateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); - size += ProtoSize::bool_(1, this->supports_current_temperature); - size += ProtoSize::bool_(1, this->supports_two_point_target_temperature); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_bool_(1, this->supports_current_temperature); + size += ProtoSize::calc_bool_(1, this->supports_two_point_target_temperature); if (!this->supported_modes->empty()) { for (const auto &it : *this->supported_modes) { - size += ProtoSize::uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } - size += ProtoSize::float_(1, this->visual_min_temperature); - size += ProtoSize::float_(1, this->visual_max_temperature); - size += ProtoSize::float_(1, this->visual_target_temperature_step); - size += ProtoSize::bool_(1, this->supports_action); + size += ProtoSize::calc_float(1, this->visual_min_temperature); + size += ProtoSize::calc_float(1, this->visual_max_temperature); + size += ProtoSize::calc_float(1, this->visual_target_temperature_step); + size += ProtoSize::calc_bool_(1, this->supports_action); if (!this->supported_fan_modes->empty()) { for (const auto &it : *this->supported_fan_modes) { - size += ProtoSize::uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } if (!this->supported_swing_modes->empty()) { for (const auto &it : *this->supported_swing_modes) { - size += ProtoSize::uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } if (!this->supported_custom_fan_modes->empty()) { for (const char *it : *this->supported_custom_fan_modes) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } if (!this->supported_presets->empty()) { for (const auto &it : *this->supported_presets) { - size += ProtoSize::uint32_force(2, static_cast(it)); + size += ProtoSize::calc_uint32_force(2, static_cast(it)); } } if (!this->supported_custom_presets->empty()) { for (const char *it : *this->supported_custom_presets) { - size += ProtoSize::length_force(2, strlen(it)); + size += ProtoSize::calc_length_force(2, strlen(it)); } } - size += ProtoSize::bool_(2, this->disabled_by_default); + size += ProtoSize::calc_bool_(2, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(2, this->icon.size()); + size += ProtoSize::calc_length(2, this->icon.size()); #endif - size += ProtoSize::uint32(2, static_cast(this->entity_category)); - size += ProtoSize::float_(2, this->visual_current_temperature_step); - size += ProtoSize::bool_(2, this->supports_current_humidity); - size += ProtoSize::bool_(2, this->supports_target_humidity); - size += ProtoSize::float_(2, this->visual_min_humidity); - size += ProtoSize::float_(2, this->visual_max_humidity); + size += ProtoSize::calc_uint32(2, static_cast(this->entity_category)); + size += ProtoSize::calc_float(2, this->visual_current_temperature_step); + size += ProtoSize::calc_bool_(2, this->supports_current_humidity); + size += ProtoSize::calc_bool_(2, this->supports_target_humidity); + size += ProtoSize::calc_float(2, this->visual_min_humidity); + size += ProtoSize::calc_float(2, this->visual_max_humidity); #ifdef USE_DEVICES - size += ProtoSize::uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif - size += ProtoSize::uint32(2, this->feature_flags); + size += ProtoSize::calc_uint32(2, this->feature_flags); return size; } void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { @@ -1427,22 +1427,22 @@ void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ClimateStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::uint32(1, static_cast(this->mode)); - size += ProtoSize::float_(1, this->current_temperature); - size += ProtoSize::float_(1, this->target_temperature); - size += ProtoSize::float_(1, this->target_temperature_low); - size += ProtoSize::float_(1, this->target_temperature_high); - size += ProtoSize::uint32(1, static_cast(this->action)); - size += ProtoSize::uint32(1, static_cast(this->fan_mode)); - size += ProtoSize::uint32(1, static_cast(this->swing_mode)); - size += ProtoSize::length(1, this->custom_fan_mode.size()); - size += ProtoSize::uint32(1, static_cast(this->preset)); - size += ProtoSize::length(1, this->custom_preset.size()); - size += ProtoSize::float_(1, this->current_humidity); - size += ProtoSize::float_(1, this->target_humidity); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->mode)); + size += ProtoSize::calc_float(1, this->current_temperature); + size += ProtoSize::calc_float(1, this->target_temperature); + size += ProtoSize::calc_float(1, this->target_temperature_low); + size += ProtoSize::calc_float(1, this->target_temperature_high); + size += ProtoSize::calc_uint32(1, static_cast(this->action)); + size += ProtoSize::calc_uint32(1, static_cast(this->fan_mode)); + size += ProtoSize::calc_uint32(1, static_cast(this->swing_mode)); + size += ProtoSize::calc_length(1, this->custom_fan_mode.size()); + size += ProtoSize::calc_uint32(1, static_cast(this->preset)); + size += ProtoSize::calc_length(1, this->custom_preset.size()); + size += ProtoSize::calc_float(1, this->current_humidity); + size += ProtoSize::calc_float(1, this->target_humidity); #ifdef USE_DEVICES - size += ProtoSize::uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif return size; } @@ -1561,26 +1561,26 @@ void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size += ProtoSize::float_(1, this->min_temperature); - size += ProtoSize::float_(1, this->max_temperature); - size += ProtoSize::float_(1, this->target_temperature_step); + size += ProtoSize::calc_float(1, this->min_temperature); + size += ProtoSize::calc_float(1, this->max_temperature); + size += ProtoSize::calc_float(1, this->target_temperature_step); if (!this->supported_modes->empty()) { for (const auto &it : *this->supported_modes) { - size += ProtoSize::uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } - size += ProtoSize::uint32(1, this->supported_features); + size += ProtoSize::calc_uint32(1, this->supported_features); return size; } void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { @@ -1597,16 +1597,16 @@ void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t WaterHeaterStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::float_(1, this->current_temperature); - size += ProtoSize::float_(1, this->target_temperature); - size += ProtoSize::uint32(1, static_cast(this->mode)); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->current_temperature); + size += ProtoSize::calc_float(1, this->target_temperature); + size += ProtoSize::calc_uint32(1, static_cast(this->mode)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size += ProtoSize::uint32(1, this->state); - size += ProtoSize::float_(1, this->target_temperature_low); - size += ProtoSize::float_(1, this->target_temperature_high); + size += ProtoSize::calc_uint32(1, this->state); + size += ProtoSize::calc_float(1, this->target_temperature_low); + size += ProtoSize::calc_float(1, this->target_temperature_high); return size; } bool WaterHeaterCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -1672,22 +1672,22 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesNumberResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::float_(1, this->min_value); - size += ProtoSize::float_(1, this->max_value); - size += ProtoSize::float_(1, this->step); - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->unit_of_measurement.size()); - size += ProtoSize::uint32(1, static_cast(this->mode)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_float(1, this->min_value); + size += ProtoSize::calc_float(1, this->max_value); + size += ProtoSize::calc_float(1, this->step); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); + size += ProtoSize::calc_uint32(1, static_cast(this->mode)); + size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1701,11 +1701,11 @@ void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t NumberStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::float_(1, this->state); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->state); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1754,21 +1754,21 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesSelectResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif if (!this->options->empty()) { for (const char *it : *this->options) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1782,11 +1782,11 @@ void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t SelectStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->state.size()); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->state.size()); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1845,23 +1845,23 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesSirenResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); if (!this->tones->empty()) { for (const char *it : *this->tones) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::bool_(1, this->supports_duration); - size += ProtoSize::bool_(1, this->supports_volume); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->supports_duration); + size += ProtoSize::calc_bool_(1, this->supports_volume); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1874,10 +1874,10 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t SirenStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1956,20 +1956,20 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesLockResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::bool_(1, this->assumed_state); - size += ProtoSize::bool_(1, this->supports_open); - size += ProtoSize::bool_(1, this->requires_code); - size += ProtoSize::length(1, this->code_format.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->assumed_state); + size += ProtoSize::calc_bool_(1, this->supports_open); + size += ProtoSize::calc_bool_(1, this->requires_code); + size += ProtoSize::calc_length(1, this->code_format.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -1982,10 +1982,10 @@ void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t LockStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::uint32(1, static_cast(this->state)); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -2046,17 +2046,17 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesButtonResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -2093,11 +2093,11 @@ void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer &buffer) const { } uint32_t MediaPlayerSupportedFormat::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->format.size()); - size += ProtoSize::uint32(1, this->sample_rate); - size += ProtoSize::uint32(1, this->num_channels); - size += ProtoSize::uint32(1, static_cast(this->purpose)); - size += ProtoSize::uint32(1, this->sample_bytes); + size += ProtoSize::calc_length(1, this->format.size()); + size += ProtoSize::calc_uint32(1, this->sample_rate); + size += ProtoSize::calc_uint32(1, this->num_channels); + size += ProtoSize::calc_uint32(1, static_cast(this->purpose)); + size += ProtoSize::calc_uint32(1, this->sample_bytes); return size; } void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2120,24 +2120,24 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::bool_(1, this->supports_pause); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->supports_pause); if (!this->supported_formats.empty()) { for (const auto &it : this->supported_formats) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size += ProtoSize::uint32(1, this->feature_flags); + size += ProtoSize::calc_uint32(1, this->feature_flags); return size; } void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2151,12 +2151,12 @@ void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t MediaPlayerStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::uint32(1, static_cast(this->state)); - size += ProtoSize::float_(1, this->volume); - size += ProtoSize::bool_(1, this->muted); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); + size += ProtoSize::calc_float(1, this->volume); + size += ProtoSize::calc_bool_(1, this->muted); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -2234,10 +2234,10 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothLERawAdvertisement::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::sint32(1, this->rssi); - size += ProtoSize::uint32(1, this->address_type); - size += ProtoSize::length(1, this->data_len); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_sint32(1, this->rssi); + size += ProtoSize::calc_uint32(1, this->address_type); + size += ProtoSize::calc_length(1, this->data_len); return size; } void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2248,7 +2248,7 @@ void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer &buffer) cons uint32_t BluetoothLERawAdvertisementsResponse::calculate_size() const { uint32_t size = 0; for (uint16_t i = 0; i < this->advertisements_len; i++) { - size += ProtoSize::message_force(1, this->advertisements[i].calculate_size()); + size += ProtoSize::calc_message_force(1, this->advertisements[i].calculate_size()); } return size; } @@ -2279,10 +2279,10 @@ void BluetoothDeviceConnectionResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothDeviceConnectionResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::bool_(1, this->connected); - size += ProtoSize::uint32(1, this->mtu); - size += ProtoSize::int32(1, this->error); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_bool_(1, this->connected); + size += ProtoSize::calc_uint32(1, this->mtu); + size += ProtoSize::calc_int32(1, this->error); return size; } bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2306,11 +2306,11 @@ void BluetoothGATTDescriptor::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothGATTDescriptor::calculate_size() const { uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size += ProtoSize::uint64_force(1, this->uuid[0]); - size += ProtoSize::uint64_force(1, this->uuid[1]); + size += ProtoSize::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_uint64_force(1, this->uuid[1]); } - size += ProtoSize::uint32(1, this->handle); - size += ProtoSize::uint32(1, this->short_uuid); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_uint32(1, this->short_uuid); return size; } void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { @@ -2328,17 +2328,17 @@ void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothGATTCharacteristic::calculate_size() const { uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size += ProtoSize::uint64_force(1, this->uuid[0]); - size += ProtoSize::uint64_force(1, this->uuid[1]); + size += ProtoSize::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_uint64_force(1, this->uuid[1]); } - size += ProtoSize::uint32(1, this->handle); - size += ProtoSize::uint32(1, this->properties); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_uint32(1, this->properties); if (!this->descriptors.empty()) { for (const auto &it : this->descriptors) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size += ProtoSize::uint32(1, this->short_uuid); + size += ProtoSize::calc_uint32(1, this->short_uuid); return size; } void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { @@ -2355,16 +2355,16 @@ void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothGATTService::calculate_size() const { uint32_t size = 0; if (this->uuid[0] != 0 || this->uuid[1] != 0) { - size += ProtoSize::uint64_force(1, this->uuid[0]); - size += ProtoSize::uint64_force(1, this->uuid[1]); + size += ProtoSize::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_uint64_force(1, this->uuid[1]); } - size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::calc_uint32(1, this->handle); if (!this->characteristics.empty()) { for (const auto &it : this->characteristics) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size += ProtoSize::uint32(1, this->short_uuid); + size += ProtoSize::calc_uint32(1, this->short_uuid); return size; } void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2375,10 +2375,10 @@ void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTGetServicesResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); + size += ProtoSize::calc_uint64(1, this->address); if (!this->services.empty()) { for (const auto &it : this->services) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } return size; @@ -2388,7 +2388,7 @@ void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer &buffer) cons } uint32_t BluetoothGATTGetServicesDoneResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); + size += ProtoSize::calc_uint64(1, this->address); return size; } bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2411,9 +2411,9 @@ void BluetoothGATTReadResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTReadResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::uint32(1, this->handle); - size += ProtoSize::length(1, this->data_len_); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_length(1, this->data_len_); return size; } bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2505,9 +2505,9 @@ void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTNotifyDataResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::uint32(1, this->handle); - size += ProtoSize::length(1, this->data_len_); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_length(1, this->data_len_); return size; } void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2521,11 +2521,11 @@ void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothConnectionsFreeResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->free); - size += ProtoSize::uint32(1, this->limit); + size += ProtoSize::calc_uint32(1, this->free); + size += ProtoSize::calc_uint32(1, this->limit); for (const auto &it : this->allocated) { if (it != 0) { - size += ProtoSize::uint64_force(1, it); + size += ProtoSize::calc_uint64_force(1, it); } } return size; @@ -2537,9 +2537,9 @@ void BluetoothGATTErrorResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTErrorResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::uint32(1, this->handle); - size += ProtoSize::int32(1, this->error); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_int32(1, this->error); return size; } void BluetoothGATTWriteResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2548,8 +2548,8 @@ void BluetoothGATTWriteResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTWriteResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); return size; } void BluetoothGATTNotifyResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2558,8 +2558,8 @@ void BluetoothGATTNotifyResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothGATTNotifyResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::uint32(1, this->handle); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); return size; } void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2569,9 +2569,9 @@ void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothDevicePairingResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::bool_(1, this->paired); - size += ProtoSize::int32(1, this->error); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_bool_(1, this->paired); + size += ProtoSize::calc_int32(1, this->error); return size; } void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2581,9 +2581,9 @@ void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothDeviceUnpairingResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::bool_(1, this->success); - size += ProtoSize::int32(1, this->error); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_int32(1, this->error); return size; } void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2593,9 +2593,9 @@ void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothDeviceClearCacheResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint64(1, this->address); - size += ProtoSize::bool_(1, this->success); - size += ProtoSize::int32(1, this->error); + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_int32(1, this->error); return size; } void BluetoothScannerStateResponse::encode(ProtoWriteBuffer &buffer) const { @@ -2605,9 +2605,9 @@ void BluetoothScannerStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t BluetoothScannerStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, static_cast(this->state)); - size += ProtoSize::uint32(1, static_cast(this->mode)); - size += ProtoSize::uint32(1, static_cast(this->configured_mode)); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); + size += ProtoSize::calc_uint32(1, static_cast(this->mode)); + size += ProtoSize::calc_uint32(1, static_cast(this->configured_mode)); return size; } bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2642,9 +2642,9 @@ void VoiceAssistantAudioSettings::encode(ProtoWriteBuffer &buffer) const { } uint32_t VoiceAssistantAudioSettings::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, this->noise_suppression_level); - size += ProtoSize::uint32(1, this->auto_gain); - size += ProtoSize::float_(1, this->volume_multiplier); + size += ProtoSize::calc_uint32(1, this->noise_suppression_level); + size += ProtoSize::calc_uint32(1, this->auto_gain); + size += ProtoSize::calc_float(1, this->volume_multiplier); return size; } void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { @@ -2656,11 +2656,11 @@ void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { } uint32_t VoiceAssistantRequest::calculate_size() const { uint32_t size = 0; - size += ProtoSize::bool_(1, this->start); - size += ProtoSize::length(1, this->conversation_id.size()); - size += ProtoSize::uint32(1, this->flags); - size += ProtoSize::message(1, this->audio_settings.calculate_size()); - size += ProtoSize::length(1, this->wake_word_phrase.size()); + size += ProtoSize::calc_bool_(1, this->start); + size += ProtoSize::calc_length(1, this->conversation_id.size()); + size += ProtoSize::calc_uint32(1, this->flags); + size += ProtoSize::calc_message(1, this->audio_settings.calculate_size()); + size += ProtoSize::calc_length(1, this->wake_word_phrase.size()); return size; } bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2740,8 +2740,8 @@ void VoiceAssistantAudio::encode(ProtoWriteBuffer &buffer) const { } uint32_t VoiceAssistantAudio::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->data_len); - size += ProtoSize::bool_(1, this->end); + size += ProtoSize::calc_length(1, this->data_len); + size += ProtoSize::calc_bool_(1, this->end); return size; } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2810,7 +2810,7 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t VoiceAssistantAnnounceFinished::calculate_size() const { uint32_t size = 0; - size += ProtoSize::bool_(1, this->success); + size += ProtoSize::calc_bool_(1, this->success); return size; } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { @@ -2822,11 +2822,11 @@ void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { } uint32_t VoiceAssistantWakeWord::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->id.size()); - size += ProtoSize::length(1, this->wake_word.size()); + size += ProtoSize::calc_length(1, this->id.size()); + size += ProtoSize::calc_length(1, this->wake_word.size()); if (!this->trained_languages.empty()) { for (const auto &it : this->trained_languages) { - size += ProtoSize::length_force(1, it.size()); + size += ProtoSize::calc_length_force(1, it.size()); } } return size; @@ -2895,15 +2895,15 @@ uint32_t VoiceAssistantConfigurationResponse::calculate_size() const { uint32_t size = 0; if (!this->available_wake_words.empty()) { for (const auto &it : this->available_wake_words) { - size += ProtoSize::message_force(1, it.calculate_size()); + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } if (!this->active_wake_words->empty()) { for (const auto &it : *this->active_wake_words) { - size += ProtoSize::length_force(1, it.size()); + size += ProtoSize::calc_length_force(1, it.size()); } } - size += ProtoSize::uint32(1, this->max_active_wake_words); + size += ProtoSize::calc_uint32(1, this->max_active_wake_words); return size; } bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -2936,19 +2936,19 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) con } uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::uint32(1, this->supported_features); - size += ProtoSize::bool_(1, this->requires_code); - size += ProtoSize::bool_(1, this->requires_code_to_arm); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, this->supported_features); + size += ProtoSize::calc_bool_(1, this->requires_code); + size += ProtoSize::calc_bool_(1, this->requires_code_to_arm); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -2961,10 +2961,10 @@ void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t AlarmControlPanelStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::uint32(1, static_cast(this->state)); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3025,20 +3025,20 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesTextResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::uint32(1, this->min_length); - size += ProtoSize::uint32(1, this->max_length); - size += ProtoSize::length(1, this->pattern.size()); - size += ProtoSize::uint32(1, static_cast(this->mode)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, this->min_length); + size += ProtoSize::calc_uint32(1, this->max_length); + size += ProtoSize::calc_length(1, this->pattern.size()); + size += ProtoSize::calc_uint32(1, static_cast(this->mode)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3052,11 +3052,11 @@ void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t TextStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->state.size()); - size += ProtoSize::bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->state.size()); + size += ProtoSize::calc_bool_(1, this->missing_state); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3110,16 +3110,16 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesDateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3135,13 +3135,13 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t DateStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->missing_state); - size += ProtoSize::uint32(1, this->year); - size += ProtoSize::uint32(1, this->month); - size += ProtoSize::uint32(1, this->day); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_uint32(1, this->year); + size += ProtoSize::calc_uint32(1, this->month); + size += ProtoSize::calc_uint32(1, this->day); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3193,16 +3193,16 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesTimeResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3218,13 +3218,13 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t TimeStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->missing_state); - size += ProtoSize::uint32(1, this->hour); - size += ProtoSize::uint32(1, this->minute); - size += ProtoSize::uint32(1, this->second); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_uint32(1, this->hour); + size += ProtoSize::calc_uint32(1, this->minute); + size += ProtoSize::calc_uint32(1, this->second); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3280,22 +3280,22 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesEventResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); if (!this->event_types->empty()) { for (const char *it : *this->event_types) { - size += ProtoSize::length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3308,10 +3308,10 @@ void EventResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t EventResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->event_type.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->event_type.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3336,20 +3336,20 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesValveResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); - size += ProtoSize::bool_(1, this->assumed_state); - size += ProtoSize::bool_(1, this->supports_position); - size += ProtoSize::bool_(1, this->supports_stop); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->assumed_state); + size += ProtoSize::calc_bool_(1, this->supports_position); + size += ProtoSize::calc_bool_(1, this->supports_stop); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3363,11 +3363,11 @@ void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ValveStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::float_(1, this->position); - size += ProtoSize::uint32(1, static_cast(this->current_operation)); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->position); + size += ProtoSize::calc_uint32(1, static_cast(this->current_operation)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3419,16 +3419,16 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesDateTimeResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3442,11 +3442,11 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t DateTimeStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->missing_state); - size += ProtoSize::fixed32(1, this->epoch_seconds); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_fixed32(1, this->epoch_seconds); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3493,17 +3493,17 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesUpdateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); - size += ProtoSize::length(1, this->device_class.size()); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3524,18 +3524,18 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t UpdateStateResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::bool_(1, this->missing_state); - size += ProtoSize::bool_(1, this->in_progress); - size += ProtoSize::bool_(1, this->has_progress); - size += ProtoSize::float_(1, this->progress); - size += ProtoSize::length(1, this->current_version.size()); - size += ProtoSize::length(1, this->latest_version.size()); - size += ProtoSize::length(1, this->title.size()); - size += ProtoSize::length(1, this->release_summary.size()); - size += ProtoSize::length(1, this->release_url.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool_(1, this->in_progress); + size += ProtoSize::calc_bool_(1, this->has_progress); + size += ProtoSize::calc_float(1, this->progress); + size += ProtoSize::calc_length(1, this->current_version.size()); + size += ProtoSize::calc_length(1, this->latest_version.size()); + size += ProtoSize::calc_length(1, this->title.size()); + size += ProtoSize::calc_length(1, this->release_summary.size()); + size += ProtoSize::calc_length(1, this->release_url.size()); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif return size; } @@ -3581,7 +3581,7 @@ bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited valu void ZWaveProxyFrame::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bytes(1, this->data, this->data_len); } uint32_t ZWaveProxyFrame::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->data_len); + size += ProtoSize::calc_length(1, this->data_len); return size; } bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -3612,8 +3612,8 @@ void ZWaveProxyRequest::encode(ProtoWriteBuffer &buffer) const { } uint32_t ZWaveProxyRequest::calculate_size() const { uint32_t size = 0; - size += ProtoSize::uint32(1, static_cast(this->type)); - size += ProtoSize::length(1, this->data_len); + size += ProtoSize::calc_uint32(1, static_cast(this->type)); + size += ProtoSize::calc_length(1, this->data_len); return size; } #endif @@ -3634,18 +3634,18 @@ void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const { } uint32_t ListEntitiesInfraredResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::length(1, this->object_id.size()); - size += ProtoSize::fixed32(1, this->key); - size += ProtoSize::length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); #ifdef USE_ENTITY_ICON - size += ProtoSize::length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::bool_(1, this->disabled_by_default); - size += ProtoSize::uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size += ProtoSize::uint32(1, this->capabilities); + size += ProtoSize::calc_uint32(1, this->capabilities); return size; } #endif @@ -3703,12 +3703,12 @@ void InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer) const { uint32_t InfraredRFReceiveEvent::calculate_size() const { uint32_t size = 0; #ifdef USE_DEVICES - size += ProtoSize::uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size += ProtoSize::fixed32(1, this->key); + size += ProtoSize::calc_fixed32(1, this->key); if (!this->timings->empty()) { for (const auto &it : *this->timings) { - size += ProtoSize::sint32_force(1, it); + size += ProtoSize::calc_sint32_force(1, it); } } return size; diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 410e604b99f..cf03f48be84 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -596,59 +596,69 @@ class ProtoSize { // Static methods that RETURN size contribution (no ProtoSize object needed). // Used by generated calculate_size() methods to accumulate into a plain uint32_t register. - static constexpr uint32_t int32(uint32_t field_id_size, int32_t value) { + static constexpr uint32_t calc_int32(uint32_t field_id_size, int32_t value) { return value ? field_id_size + (value < 0 ? 10 : varint(static_cast(value))) : 0; } - static constexpr uint32_t int32_force(uint32_t field_id_size, int32_t value) { + static constexpr uint32_t calc_int32_force(uint32_t field_id_size, int32_t value) { return field_id_size + (value < 0 ? 10 : varint(static_cast(value))); } - static constexpr uint32_t uint32(uint32_t field_id_size, uint32_t value) { + static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value) { return value ? field_id_size + varint(value) : 0; } - static constexpr uint32_t uint32_force(uint32_t field_id_size, uint32_t value) { + static constexpr uint32_t calc_uint32_force(uint32_t field_id_size, uint32_t value) { return field_id_size + varint(value); } - static constexpr uint32_t bool_(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } - static constexpr uint32_t bool_force(uint32_t field_id_size) { return field_id_size + 1; } - static constexpr uint32_t float_(uint32_t field_id_size, float value) { + static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } + static constexpr uint32_t calc_bool_force(uint32_t field_id_size) { return field_id_size + 1; } + static constexpr uint32_t calc_float(uint32_t field_id_size, float value) { return value != 0.0f ? field_id_size + 4 : 0; } - static constexpr uint32_t fixed32(uint32_t field_id_size, uint32_t value) { return value ? field_id_size + 4 : 0; } - static constexpr uint32_t sfixed32(uint32_t field_id_size, int32_t value) { return value ? field_id_size + 4 : 0; } - static constexpr uint32_t sint32(uint32_t field_id_size, int32_t value) { + static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + 4 : 0; + } + static constexpr uint32_t calc_sfixed32(uint32_t field_id_size, int32_t value) { + return value ? field_id_size + 4 : 0; + } + static constexpr uint32_t calc_sint32(uint32_t field_id_size, int32_t value) { return value ? field_id_size + varint(encode_zigzag32(value)) : 0; } - static constexpr uint32_t sint32_force(uint32_t field_id_size, int32_t value) { + static constexpr uint32_t calc_sint32_force(uint32_t field_id_size, int32_t value) { return field_id_size + varint(encode_zigzag32(value)); } - static constexpr uint32_t int64(uint32_t field_id_size, int64_t value) { + static constexpr uint32_t calc_int64(uint32_t field_id_size, int64_t value) { return value ? field_id_size + varint(value) : 0; } - static constexpr uint32_t int64_force(uint32_t field_id_size, int64_t value) { return field_id_size + varint(value); } - static constexpr uint32_t uint64(uint32_t field_id_size, uint64_t value) { - return value ? field_id_size + varint(value) : 0; - } - static constexpr uint32_t uint64_force(uint32_t field_id_size, uint64_t value) { + static constexpr uint32_t calc_int64_force(uint32_t field_id_size, int64_t value) { return field_id_size + varint(value); } - static constexpr uint32_t length(uint32_t field_id_size, size_t len) { + static constexpr uint32_t calc_uint64(uint32_t field_id_size, uint64_t value) { + return value ? field_id_size + varint(value) : 0; + } + static constexpr uint32_t calc_uint64_force(uint32_t field_id_size, uint64_t value) { + return field_id_size + varint(value); + } + static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) { return len ? field_id_size + varint(static_cast(len)) + static_cast(len) : 0; } - static constexpr uint32_t length_force(uint32_t field_id_size, size_t len) { + static constexpr uint32_t calc_length_force(uint32_t field_id_size, size_t len) { return field_id_size + varint(static_cast(len)) + static_cast(len); } - static constexpr uint32_t sint64(uint32_t field_id_size, int64_t value) { + static constexpr uint32_t calc_sint64(uint32_t field_id_size, int64_t value) { return value ? field_id_size + varint(encode_zigzag64(value)) : 0; } - static constexpr uint32_t sint64_force(uint32_t field_id_size, int64_t value) { + static constexpr uint32_t calc_sint64_force(uint32_t field_id_size, int64_t value) { return field_id_size + varint(encode_zigzag64(value)); } - static constexpr uint32_t fixed64(uint32_t field_id_size, uint64_t value) { return value ? field_id_size + 8 : 0; } - static constexpr uint32_t sfixed64(uint32_t field_id_size, int64_t value) { return value ? field_id_size + 8 : 0; } - static constexpr uint32_t message(uint32_t field_id_size, uint32_t nested_size) { + static constexpr uint32_t calc_fixed64(uint32_t field_id_size, uint64_t value) { + return value ? field_id_size + 8 : 0; + } + static constexpr uint32_t calc_sfixed64(uint32_t field_id_size, int64_t value) { + return value ? field_id_size + 8 : 0; + } + static constexpr uint32_t calc_message(uint32_t field_id_size, uint32_t nested_size) { return nested_size ? field_id_size + varint(nested_size) + nested_size : 0; } - static constexpr uint32_t message_force(uint32_t field_id_size, uint32_t nested_size) { + static constexpr uint32_t calc_message_force(uint32_t field_id_size, uint32_t nested_size) { return field_id_size + varint(nested_size) + nested_size; } }; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index e5106c85001..039222b7c2b 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -279,7 +279,7 @@ class TypeInfo(ABC): value_expr: Optional value expression (defaults to name) """ field_id_size = self.calculate_field_id_size() - method = f"{base_method}_force" if force else base_method + method = f"calc_{base_method}_force" if force else f"calc_{base_method}" value = value_expr or name return f"size += ProtoSize::{method}({field_id_size}, {value});" @@ -410,7 +410,7 @@ class DoubleType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::fixed64({field_id_size}, {name});" + return f"size += ProtoSize::calc_fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -434,7 +434,7 @@ class FloatType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::float_({field_id_size}, {name});" + return f"size += ProtoSize::calc_float({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -518,7 +518,7 @@ class Fixed64Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::fixed64({field_id_size}, {name});" + return f"size += ProtoSize::calc_fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -542,7 +542,7 @@ class Fixed32Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::fixed32({field_id_size}, {name});" + return f"size += ProtoSize::calc_fixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -654,11 +654,11 @@ class StringType(TypeInfo): if name == "it": # For repeated fields, we need to use length_force which includes field ID field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::length_force({field_id_size}, it.size());" + return f"size += ProtoSize::calc_length_force({field_id_size}, it.size());" # For messages that need encoding, use the StringRef size field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::length({field_id_size}, this->{self.field_name}_ref_.size());" + return f"size += ProtoSize::calc_length({field_id_size}, this->{self.field_name}_ref_.size());" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string @@ -722,7 +722,7 @@ class MessageType(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - method = "message_force" if force else "message" + method = "calc_message_force" if force else "calc_message" return f"size += ProtoSize::{method}({field_id_size}, {name}.calculate_size());" def get_estimated_size(self) -> int: @@ -824,7 +824,7 @@ class BytesType(TypeInfo): ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}_len_);" + return f"size += ProtoSize::calc_length({self.calculate_field_id_size()}, this->{self.field_name}_len_);" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical bytes @@ -899,7 +899,7 @@ class PointerToBytesBufferType(PointerToBufferTypeBase): ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}_len);" + return f"size += ProtoSize::calc_length({self.calculate_field_id_size()}, this->{self.field_name}_len);" class PointerToStringBufferType(PointerToBufferTypeBase): @@ -941,7 +941,7 @@ class PointerToStringBufferType(PointerToBufferTypeBase): return f'dump_field(out, "{self.name}", this->{self.field_name});' def get_size_calculation(self, name: str, force: bool = False) -> str: - return f"size += ProtoSize::length({self.calculate_field_id_size()}, this->{self.field_name}.size());" + return f"size += ProtoSize::calc_length({self.calculate_field_id_size()}, this->{self.field_name}.size());" def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string @@ -1105,9 +1105,9 @@ class FixedArrayBytesType(TypeInfo): if force: # For repeated fields, always calculate size (no zero check) - return f"size += ProtoSize::length_force({field_id_size}, {length_field});" + return f"size += ProtoSize::calc_length_force({field_id_size}, {length_field});" # For non-repeated fields, length already checks for zero - return f"size += ProtoSize::length({field_id_size}, {length_field});" + return f"size += ProtoSize::calc_length({field_id_size}, {length_field});" def get_estimated_size(self) -> int: # Estimate based on typical BLE advertisement size @@ -1192,7 +1192,7 @@ class SFixed32Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::sfixed32({field_id_size}, {name});" + return f"size += ProtoSize::calc_sfixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -1216,7 +1216,7 @@ class SFixed64Type(TypeInfo): def get_size_calculation(self, name: str, force: bool = False) -> str: field_id_size = self.calculate_field_id_size() - return f"size += ProtoSize::sfixed64({field_id_size}, {name});" + return f"size += ProtoSize::calc_sfixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -1703,7 +1703,7 @@ class RepeatedTypeInfo(TypeInfo): empty_check = f"{name}->empty()" if self._use_pointer else f"{name}.empty()" o = f"if (!{empty_check}) {{\n" o += f" for (const auto &it : {container_ref}) {{\n" - o += f" size += ProtoSize::message_force({field_id_size}, it.calculate_size());\n" + o += f" size += ProtoSize::calc_message_force({field_id_size}, it.calculate_size());\n" o += " }\n" o += "}" return o @@ -1728,7 +1728,7 @@ class RepeatedTypeInfo(TypeInfo): if self._use_pointer and "const char" in self._container_no_template: field_id_size = self.calculate_field_id_size() o += f" for (const char *it : {container_ref}) {{\n" - o += f" size += ProtoSize::length_force({field_id_size}, strlen(it));\n" + o += f" size += ProtoSize::calc_length_force({field_id_size}, strlen(it));\n" else: auto_ref = "" if self._ti_is_bool else "&" o += f" for (const auto {auto_ref}it : {container_ref}) {{\n" From 3a5f03d0a33205f9643813963415fed38e53ae7d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:22:02 -1000 Subject: [PATCH 20/42] naming --- esphome/components/api/api_pb2.cpp | 170 ++++++++++++++-------------- script/api_protobuf/api_protobuf.py | 2 +- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index d60ef1acd0e..d8703aa416e 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -134,7 +134,7 @@ uint32_t DeviceInfoResponse::calculate_size() const { size += ProtoSize::calc_length(1, this->compilation_time.size()); size += ProtoSize::calc_length(1, this->model.size()); #ifdef USE_DEEP_SLEEP - size += ProtoSize::calc_bool_(1, this->has_deep_sleep); + size += ProtoSize::calc_bool(1, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME size += ProtoSize::calc_length(1, this->project_name.size()); @@ -160,7 +160,7 @@ uint32_t DeviceInfoResponse::calculate_size() const { size += ProtoSize::calc_length(2, this->bluetooth_mac_address.size()); #endif #ifdef USE_API_NOISE - size += ProtoSize::calc_bool_(2, this->api_encryption_supported); + size += ProtoSize::calc_bool(2, this->api_encryption_supported); #endif #ifdef USE_DEVICES for (const auto &it : this->devices) { @@ -205,8 +205,8 @@ uint32_t ListEntitiesBinarySensorResponse::calculate_size() const { size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->name.size()); size += ProtoSize::calc_length(1, this->device_class.size()); - size += ProtoSize::calc_bool_(1, this->is_status_binary_sensor); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->is_status_binary_sensor); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif @@ -227,8 +227,8 @@ void BinarySensorStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t BinarySensorStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->state); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -259,16 +259,16 @@ uint32_t ListEntitiesCoverResponse::calculate_size() const { size += ProtoSize::calc_length(1, this->object_id.size()); size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->name.size()); - size += ProtoSize::calc_bool_(1, this->assumed_state); - size += ProtoSize::calc_bool_(1, this->supports_position); - size += ProtoSize::calc_bool_(1, this->supports_tilt); + size += ProtoSize::calc_bool(1, this->assumed_state); + size += ProtoSize::calc_bool(1, this->supports_position); + size += ProtoSize::calc_bool(1, this->supports_tilt); size += ProtoSize::calc_length(1, this->device_class.size()); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); - size += ProtoSize::calc_bool_(1, this->supports_stop); + size += ProtoSize::calc_bool(1, this->supports_stop); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -358,11 +358,11 @@ uint32_t ListEntitiesFanResponse::calculate_size() const { size += ProtoSize::calc_length(1, this->object_id.size()); size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->name.size()); - size += ProtoSize::calc_bool_(1, this->supports_oscillation); - size += ProtoSize::calc_bool_(1, this->supports_speed); - size += ProtoSize::calc_bool_(1, this->supports_direction); + size += ProtoSize::calc_bool(1, this->supports_oscillation); + size += ProtoSize::calc_bool(1, this->supports_speed); + size += ProtoSize::calc_bool(1, this->supports_direction); size += ProtoSize::calc_int32(1, this->supported_speed_count); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif @@ -391,8 +391,8 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t FanStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->state); - size += ProtoSize::calc_bool_(1, this->oscillating); + size += ProtoSize::calc_bool(1, this->state); + size += ProtoSize::calc_bool(1, this->oscillating); size += ProtoSize::calc_uint32(1, static_cast(this->direction)); size += ProtoSize::calc_int32(1, this->speed_level); size += ProtoSize::calc_length(1, this->preset_mode.size()); @@ -501,7 +501,7 @@ uint32_t ListEntitiesLightResponse::calculate_size() const { size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif @@ -532,7 +532,7 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t LightStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_bool(1, this->state); size += ProtoSize::calc_float(1, this->brightness); size += ProtoSize::calc_uint32(1, static_cast(this->color_mode)); size += ProtoSize::calc_float(1, this->color_brightness); @@ -687,10 +687,10 @@ uint32_t ListEntitiesSensorResponse::calculate_size() const { #endif size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); size += ProtoSize::calc_int32(1, this->accuracy_decimals); - size += ProtoSize::calc_bool_(1, this->force_update); + size += ProtoSize::calc_bool(1, this->force_update); size += ProtoSize::calc_length(1, this->device_class.size()); size += ProtoSize::calc_uint32(1, static_cast(this->state_class)); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -709,7 +709,7 @@ uint32_t SensorStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_float(1, this->state); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -740,8 +740,8 @@ uint32_t ListEntitiesSwitchResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->assumed_state); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->assumed_state); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES @@ -759,7 +759,7 @@ void SwitchStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t SwitchStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_bool(1, this->state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -814,7 +814,7 @@ uint32_t ListEntitiesTextSensorResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES @@ -834,7 +834,7 @@ uint32_t TextSensorStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->state.size()); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -880,7 +880,7 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD void NoiseEncryptionSetKeyResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t NoiseEncryptionSetKeyResponse::calculate_size() const { uint32_t size = 0; - size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_bool(1, this->success); return size; } #endif @@ -935,12 +935,12 @@ uint32_t HomeassistantActionRequest::calculate_size() const { size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size += ProtoSize::calc_bool_(1, this->is_event); + size += ProtoSize::calc_bool(1, this->is_event); #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES size += ProtoSize::calc_uint32(1, this->call_id); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size += ProtoSize::calc_bool_(1, this->wants_response); + size += ProtoSize::calc_bool(1, this->wants_response); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON size += ProtoSize::calc_length(1, this->response_template.size()); @@ -991,7 +991,7 @@ uint32_t SubscribeHomeAssistantStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_length(1, this->entity_id.size()); size += ProtoSize::calc_length(1, this->attribute.size()); - size += ProtoSize::calc_bool_(1, this->once); + size += ProtoSize::calc_bool(1, this->once); return size; } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -1236,7 +1236,7 @@ void ExecuteServiceResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t ExecuteServiceResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_uint32(1, this->call_id); - size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_bool(1, this->success); size += ProtoSize::calc_length(1, this->error_message.size()); #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON size += ProtoSize::calc_length(1, this->response_data_len); @@ -1263,7 +1263,7 @@ uint32_t ListEntitiesCameraResponse::calculate_size() const { size += ProtoSize::calc_length(1, this->object_id.size()); size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->name.size()); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif @@ -1285,7 +1285,7 @@ uint32_t CameraImageResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->data_len_); - size += ProtoSize::calc_bool_(1, this->done); + size += ProtoSize::calc_bool(1, this->done); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -1354,8 +1354,8 @@ uint32_t ListEntitiesClimateResponse::calculate_size() const { size += ProtoSize::calc_length(1, this->object_id.size()); size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->name.size()); - size += ProtoSize::calc_bool_(1, this->supports_current_temperature); - size += ProtoSize::calc_bool_(1, this->supports_two_point_target_temperature); + size += ProtoSize::calc_bool(1, this->supports_current_temperature); + size += ProtoSize::calc_bool(1, this->supports_two_point_target_temperature); if (!this->supported_modes->empty()) { for (const auto &it : *this->supported_modes) { size += ProtoSize::calc_uint32_force(1, static_cast(it)); @@ -1364,7 +1364,7 @@ uint32_t ListEntitiesClimateResponse::calculate_size() const { size += ProtoSize::calc_float(1, this->visual_min_temperature); size += ProtoSize::calc_float(1, this->visual_max_temperature); size += ProtoSize::calc_float(1, this->visual_target_temperature_step); - size += ProtoSize::calc_bool_(1, this->supports_action); + size += ProtoSize::calc_bool(1, this->supports_action); if (!this->supported_fan_modes->empty()) { for (const auto &it : *this->supported_fan_modes) { size += ProtoSize::calc_uint32_force(1, static_cast(it)); @@ -1390,14 +1390,14 @@ uint32_t ListEntitiesClimateResponse::calculate_size() const { size += ProtoSize::calc_length_force(2, strlen(it)); } } - size += ProtoSize::calc_bool_(2, this->disabled_by_default); + size += ProtoSize::calc_bool(2, this->disabled_by_default); #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(2, this->icon.size()); #endif size += ProtoSize::calc_uint32(2, static_cast(this->entity_category)); size += ProtoSize::calc_float(2, this->visual_current_temperature_step); - size += ProtoSize::calc_bool_(2, this->supports_current_humidity); - size += ProtoSize::calc_bool_(2, this->supports_target_humidity); + size += ProtoSize::calc_bool(2, this->supports_current_humidity); + size += ProtoSize::calc_bool(2, this->supports_target_humidity); size += ProtoSize::calc_float(2, this->visual_min_humidity); size += ProtoSize::calc_float(2, this->visual_max_humidity); #ifdef USE_DEVICES @@ -1567,7 +1567,7 @@ uint32_t ListEntitiesWaterHeaterResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -1681,7 +1681,7 @@ uint32_t ListEntitiesNumberResponse::calculate_size() const { size += ProtoSize::calc_float(1, this->min_value); size += ProtoSize::calc_float(1, this->max_value); size += ProtoSize::calc_float(1, this->step); - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); size += ProtoSize::calc_uint32(1, static_cast(this->mode)); @@ -1703,7 +1703,7 @@ uint32_t NumberStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_float(1, this->state); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -1765,7 +1765,7 @@ uint32_t ListEntitiesSelectResponse::calculate_size() const { size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -1784,7 +1784,7 @@ uint32_t SelectStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->state.size()); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -1851,14 +1851,14 @@ uint32_t ListEntitiesSirenResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); if (!this->tones->empty()) { for (const char *it : *this->tones) { size += ProtoSize::calc_length_force(1, strlen(it)); } } - size += ProtoSize::calc_bool_(1, this->supports_duration); - size += ProtoSize::calc_bool_(1, this->supports_volume); + size += ProtoSize::calc_bool(1, this->supports_duration); + size += ProtoSize::calc_bool(1, this->supports_volume); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -1875,7 +1875,7 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t SirenStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->state); + size += ProtoSize::calc_bool(1, this->state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -1962,11 +1962,11 @@ uint32_t ListEntitiesLockResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); - size += ProtoSize::calc_bool_(1, this->assumed_state); - size += ProtoSize::calc_bool_(1, this->supports_open); - size += ProtoSize::calc_bool_(1, this->requires_code); + size += ProtoSize::calc_bool(1, this->assumed_state); + size += ProtoSize::calc_bool(1, this->supports_open); + size += ProtoSize::calc_bool(1, this->requires_code); size += ProtoSize::calc_length(1, this->code_format.size()); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -2052,7 +2052,7 @@ uint32_t ListEntitiesButtonResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES @@ -2126,9 +2126,9 @@ uint32_t ListEntitiesMediaPlayerResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); - size += ProtoSize::calc_bool_(1, this->supports_pause); + size += ProtoSize::calc_bool(1, this->supports_pause); if (!this->supported_formats.empty()) { for (const auto &it : this->supported_formats) { size += ProtoSize::calc_message_force(1, it.calculate_size()); @@ -2154,7 +2154,7 @@ uint32_t MediaPlayerStateResponse::calculate_size() const { size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_uint32(1, static_cast(this->state)); size += ProtoSize::calc_float(1, this->volume); - size += ProtoSize::calc_bool_(1, this->muted); + size += ProtoSize::calc_bool(1, this->muted); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -2280,7 +2280,7 @@ void BluetoothDeviceConnectionResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothDeviceConnectionResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_uint64(1, this->address); - size += ProtoSize::calc_bool_(1, this->connected); + size += ProtoSize::calc_bool(1, this->connected); size += ProtoSize::calc_uint32(1, this->mtu); size += ProtoSize::calc_int32(1, this->error); return size; @@ -2570,7 +2570,7 @@ void BluetoothDevicePairingResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothDevicePairingResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_uint64(1, this->address); - size += ProtoSize::calc_bool_(1, this->paired); + size += ProtoSize::calc_bool(1, this->paired); size += ProtoSize::calc_int32(1, this->error); return size; } @@ -2582,7 +2582,7 @@ void BluetoothDeviceUnpairingResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothDeviceUnpairingResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_uint64(1, this->address); - size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_bool(1, this->success); size += ProtoSize::calc_int32(1, this->error); return size; } @@ -2594,7 +2594,7 @@ void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t BluetoothDeviceClearCacheResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_uint64(1, this->address); - size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_bool(1, this->success); size += ProtoSize::calc_int32(1, this->error); return size; } @@ -2656,7 +2656,7 @@ void VoiceAssistantRequest::encode(ProtoWriteBuffer &buffer) const { } uint32_t VoiceAssistantRequest::calculate_size() const { uint32_t size = 0; - size += ProtoSize::calc_bool_(1, this->start); + size += ProtoSize::calc_bool(1, this->start); size += ProtoSize::calc_length(1, this->conversation_id.size()); size += ProtoSize::calc_uint32(1, this->flags); size += ProtoSize::calc_message(1, this->audio_settings.calculate_size()); @@ -2741,7 +2741,7 @@ void VoiceAssistantAudio::encode(ProtoWriteBuffer &buffer) const { uint32_t VoiceAssistantAudio::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_length(1, this->data_len); - size += ProtoSize::calc_bool_(1, this->end); + size += ProtoSize::calc_bool(1, this->end); return size; } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2810,7 +2810,7 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength void VoiceAssistantAnnounceFinished::encode(ProtoWriteBuffer &buffer) const { buffer.encode_bool(1, this->success); } uint32_t VoiceAssistantAnnounceFinished::calculate_size() const { uint32_t size = 0; - size += ProtoSize::calc_bool_(1, this->success); + size += ProtoSize::calc_bool(1, this->success); return size; } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { @@ -2942,11 +2942,11 @@ uint32_t ListEntitiesAlarmControlPanelResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_uint32(1, this->supported_features); - size += ProtoSize::calc_bool_(1, this->requires_code); - size += ProtoSize::calc_bool_(1, this->requires_code_to_arm); + size += ProtoSize::calc_bool(1, this->requires_code); + size += ProtoSize::calc_bool(1, this->requires_code_to_arm); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -3031,7 +3031,7 @@ uint32_t ListEntitiesTextResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_uint32(1, this->min_length); size += ProtoSize::calc_uint32(1, this->max_length); @@ -3054,7 +3054,7 @@ uint32_t TextStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); size += ProtoSize::calc_length(1, this->state.size()); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -3116,7 +3116,7 @@ uint32_t ListEntitiesDateResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -3136,7 +3136,7 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t DateStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); size += ProtoSize::calc_uint32(1, this->year); size += ProtoSize::calc_uint32(1, this->month); size += ProtoSize::calc_uint32(1, this->day); @@ -3199,7 +3199,7 @@ uint32_t ListEntitiesTimeResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -3219,7 +3219,7 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t TimeStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); size += ProtoSize::calc_uint32(1, this->hour); size += ProtoSize::calc_uint32(1, this->minute); size += ProtoSize::calc_uint32(1, this->second); @@ -3286,7 +3286,7 @@ uint32_t ListEntitiesEventResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); if (!this->event_types->empty()) { @@ -3342,12 +3342,12 @@ uint32_t ListEntitiesValveResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); - size += ProtoSize::calc_bool_(1, this->assumed_state); - size += ProtoSize::calc_bool_(1, this->supports_position); - size += ProtoSize::calc_bool_(1, this->supports_stop); + size += ProtoSize::calc_bool(1, this->assumed_state); + size += ProtoSize::calc_bool(1, this->supports_position); + size += ProtoSize::calc_bool(1, this->supports_stop); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); #endif @@ -3425,7 +3425,7 @@ uint32_t ListEntitiesDateTimeResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -3443,7 +3443,7 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t DateTimeStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->missing_state); size += ProtoSize::calc_fixed32(1, this->epoch_seconds); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); @@ -3499,7 +3499,7 @@ uint32_t ListEntitiesUpdateResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); size += ProtoSize::calc_length(1, this->device_class.size()); #ifdef USE_DEVICES @@ -3525,9 +3525,9 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { uint32_t UpdateStateResponse::calculate_size() const { uint32_t size = 0; size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_bool_(1, this->missing_state); - size += ProtoSize::calc_bool_(1, this->in_progress); - size += ProtoSize::calc_bool_(1, this->has_progress); + size += ProtoSize::calc_bool(1, this->missing_state); + size += ProtoSize::calc_bool(1, this->in_progress); + size += ProtoSize::calc_bool(1, this->has_progress); size += ProtoSize::calc_float(1, this->progress); size += ProtoSize::calc_length(1, this->current_version.size()); size += ProtoSize::calc_length(1, this->latest_version.size()); @@ -3640,7 +3640,7 @@ uint32_t ListEntitiesInfraredResponse::calculate_size() const { #ifdef USE_ENTITY_ICON size += ProtoSize::calc_length(1, this->icon.size()); #endif - size += ProtoSize::calc_bool_(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id); diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 039222b7c2b..b00cbab37a3 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -563,7 +563,7 @@ class BoolType(TypeInfo): return f"out.append(YESNO({name}));" def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "bool_") + return self._get_simple_size_calculation(name, force, "bool") def get_estimated_size(self) -> int: return self.calculate_field_id_size() + 1 # field ID + 1 byte From cdcc5e5932c99f6127925f8f4dd24a821c4ecb86 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:22:27 -1000 Subject: [PATCH 21/42] Rename ProtoSize static methods with calc_ prefix for clang-tidy --- tests/benchmarks/proto_encode_benchmark.cpp | 795 ++++++++++++++++++++ 1 file changed, 795 insertions(+) create mode 100644 tests/benchmarks/proto_encode_benchmark.cpp diff --git a/tests/benchmarks/proto_encode_benchmark.cpp b/tests/benchmarks/proto_encode_benchmark.cpp new file mode 100644 index 00000000000..ac49e139aec --- /dev/null +++ b/tests/benchmarks/proto_encode_benchmark.cpp @@ -0,0 +1,795 @@ +/** + * Benchmark: ProtoWriteBuffer encoding performance + * + * Compares the old push_back()-based encoding against the new pre-sized + * pointer-write approach introduced in PR #14018. + * + * Build (from repo root): + * g++ -std=gnu++20 -O2 \ + * tests/benchmarks/proto_encode_benchmark.cpp \ + * -o tests/benchmarks/proto_encode_benchmark + * + * For ESP-like size-optimized builds (-Os): + * g++ -std=gnu++20 -Os \ + * tests/benchmarks/proto_encode_benchmark.cpp \ + * -o tests/benchmarks/proto_encode_benchmark + * + * Run: + * ./tests/benchmarks/proto_encode_benchmark + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================================ +// Minimal stubs to avoid pulling in the full ESPHome framework +// ============================================================================ + +namespace esphome { + +class StringRef { + public: + constexpr StringRef() : base_(""), len_(0) {} + explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {} + constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {} + explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {} + + const char *c_str() const { return base_; } + size_t size() const { return len_; } + bool empty() const { return len_ == 0; } + + private: + const char *base_; + size_t len_; +}; + +} // namespace esphome + +// ============================================================================ +// Old-style ProtoWriteBuffer (push_back based) - from dev branch +// ============================================================================ + +class OldProtoWriteBuffer { + public: + explicit OldProtoWriteBuffer(std::vector *buffer) : buffer_(buffer) {} + + void encode_varint_raw(uint32_t value) { + while (value > 0x7F) { + this->buffer_->push_back(static_cast(value | 0x80)); + value >>= 7; + } + this->buffer_->push_back(static_cast(value)); + } + + void encode_varint_raw_64(uint64_t value) { + while (value > 0x7F) { + this->buffer_->push_back(static_cast(value | 0x80)); + value >>= 7; + } + this->buffer_->push_back(static_cast(value)); + } + + void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } + + void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { + if (len == 0 && !force) + return; + this->encode_field_raw(field_id, 2); + this->encode_varint_raw(len); + size_t old_size = this->buffer_->size(); + this->buffer_->resize(old_size + len); + std::memcpy(this->buffer_->data() + old_size, string, len); + } + + void encode_string(uint32_t field_id, const esphome::StringRef &ref, bool force = false) { + this->encode_string(field_id, ref.c_str(), ref.size(), force); + } + + void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 0); + this->encode_varint_raw(value); + } + + void encode_bool(uint32_t field_id, bool value, bool force = false) { + if (!value && !force) + return; + this->encode_field_raw(field_id, 0); + this->buffer_->push_back(value ? 0x01 : 0x00); + } + + void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 5); + this->buffer_->push_back((value >> 0) & 0xFF); + this->buffer_->push_back((value >> 8) & 0xFF); + this->buffer_->push_back((value >> 16) & 0xFF); + this->buffer_->push_back((value >> 24) & 0xFF); + } + + void encode_float(uint32_t field_id, float value, bool force = false) { + if (value == 0.0f && !force) + return; + union { + float value; + uint32_t raw; + } val{}; + val.value = value; + this->encode_fixed32(field_id, val.raw); + } + + void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { + this->encode_string(field_id, reinterpret_cast(data), len, force); + } + + std::vector *get_buffer() const { return buffer_; } + + protected: + std::vector *buffer_; +}; + +// ============================================================================ +// New-style ProtoWriteBuffer (pointer-write based) - from this PR +// ============================================================================ + +class NewProtoWriteBuffer { + public: + NewProtoWriteBuffer(std::vector *buffer, size_t write_pos) + : buffer_(buffer), pos_(buffer->data() + write_pos) {} + + void encode_varint_raw(uint32_t value) { + while (value > 0x7F) { + *this->pos_++ = static_cast(value | 0x80); + value >>= 7; + } + *this->pos_++ = static_cast(value); + } + + void encode_varint_raw_64(uint64_t value) { + while (value > 0x7F) { + *this->pos_++ = static_cast(value | 0x80); + value >>= 7; + } + *this->pos_++ = static_cast(value); + } + + void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } + + void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { + if (len == 0 && !force) + return; + this->encode_field_raw(field_id, 2); + this->encode_varint_raw(len); + std::memcpy(this->pos_, string, len); + this->pos_ += len; + } + + void encode_string(uint32_t field_id, const esphome::StringRef &ref, bool force = false) { + this->encode_string(field_id, ref.c_str(), ref.size(), force); + } + + void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 0); + this->encode_varint_raw(value); + } + + void encode_bool(uint32_t field_id, bool value, bool force = false) { + if (!value && !force) + return; + this->encode_field_raw(field_id, 0); + *this->pos_++ = value ? 0x01 : 0x00; + } + + void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 5); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::memcpy(this->pos_, &value, 4); + this->pos_ += 4; +#else + *this->pos_++ = (value >> 0) & 0xFF; + *this->pos_++ = (value >> 8) & 0xFF; + *this->pos_++ = (value >> 16) & 0xFF; + *this->pos_++ = (value >> 24) & 0xFF; +#endif + } + + void encode_float(uint32_t field_id, float value, bool force = false) { + if (value == 0.0f && !force) + return; + union { + float value; + uint32_t raw; + } val{}; + val.value = value; + this->encode_fixed32(field_id, val.raw); + } + + void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { + this->encode_string(field_id, reinterpret_cast(data), len, force); + } + + uint8_t *pos() const { return pos_; } + std::vector *get_buffer() const { return buffer_; } + + protected: + std::vector *buffer_; + uint8_t *pos_; +}; + +// ============================================================================ +// ProtoSize - calculate exact encoded size (shared by both approaches) +// ============================================================================ + +class ProtoSize { + public: + static constexpr uint32_t varint(uint32_t value) { + if (value < 128) + return 1; + if (value < 16384) + return 2; + if (value < 2097152) + return 3; + if (value < 268435456) + return 4; + return 5; + } + + static constexpr uint32_t field(uint32_t field_id, uint32_t type) { return varint((field_id << 3) | (type & 0x7)); } + + static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + varint(value) : 0; + } + + static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } + + static constexpr uint32_t calc_float(uint32_t field_id_size, float value) { + return value != 0.0f ? field_id_size + 4 : 0; + } + + static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + 4 : 0; + } + + static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) { + return len ? field_id_size + varint(static_cast(len)) + static_cast(len) : 0; + } +}; + +// ============================================================================ +// Benchmark infrastructure +// ============================================================================ + +struct BenchResult { + const char *name; + double ns_per_op; + double ops_per_sec; + size_t iterations; + size_t bytes_per_op; +}; + +// Prevent compiler from optimizing away the result +template __attribute__((noinline)) void do_not_optimize(T &value) { + asm volatile("" : "+r,m"(value) : : "memory"); +} + +__attribute__((noinline)) void clobber_memory() { asm volatile("" : : : "memory"); } + +template BenchResult benchmark(const char *name, size_t bytes_per_op, Func func) { + // Warmup + for (int i = 0; i < 1000; i++) { + func(); + } + + // Determine iteration count (target ~100ms) + size_t iterations = 1000; + auto start = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < iterations; i++) { + func(); + } + auto end = std::chrono::high_resolution_clock::now(); + double elapsed_ns = std::chrono::duration_cast(end - start).count(); + double ns_per_op = elapsed_ns / iterations; + + // Scale iterations to target ~200ms + iterations = std::max(10000, static_cast(200'000'000.0 / ns_per_op)); + + // Actual benchmark run + start = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < iterations; i++) { + func(); + clobber_memory(); + } + end = std::chrono::high_resolution_clock::now(); + elapsed_ns = std::chrono::duration_cast(end - start).count(); + ns_per_op = elapsed_ns / iterations; + + return BenchResult{name, ns_per_op, 1'000'000'000.0 / ns_per_op, iterations, bytes_per_op}; +} + +void print_results(const std::vector &results) { + printf("%-50s %12s %12s %12s %10s\n", "Benchmark", "ns/op", "ops/sec", "iters", "bytes/op"); + printf("%-50s %12s %12s %12s %10s\n", std::string(50, '-').c_str(), "--------", "--------", "--------", "--------"); + for (const auto &r : results) { + printf("%-50s %12.1f %12.0f %12zu %10zu\n", r.name, r.ns_per_op, r.ops_per_sec, r.iterations, r.bytes_per_op); + } +} + +void print_comparison(const char *label, const BenchResult &old_result, const BenchResult &new_result) { + double speedup = old_result.ns_per_op / new_result.ns_per_op; + printf(" %-46s %.1fx %s\n", label, speedup, speedup > 1.0 ? "faster" : "slower"); +} + +// ============================================================================ +// Benchmark: Varint encoding +// ============================================================================ + +static void bench_varint_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + // Encode a mix of varint sizes (1-5 bytes) + writer.encode_varint_raw(0x01); // 1 byte + writer.encode_varint_raw(0x80); // 2 bytes + writer.encode_varint_raw(0x4000); // 3 bytes + writer.encode_varint_raw(0x200000); // 4 bytes + writer.encode_varint_raw(0x10000000); // 5 bytes +} + +static void bench_varint_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_varint_raw(0x01); + writer.encode_varint_raw(0x80); + writer.encode_varint_raw(0x4000); + writer.encode_varint_raw(0x200000); + writer.encode_varint_raw(0x10000000); +} + +// ============================================================================ +// Benchmark: String encoding (simulates entity names, object_ids, etc.) +// ============================================================================ + +static const char SHORT_STR[] = "sensor_1"; // 8 bytes +static const char MEDIUM_STR[] = "living_room_temperature_sensor"; // 30 bytes +static const char LONG_STR[] = + "esphome_very_long_device_name_with_many_characters_for_testing_purposes_abcdef"; // 78 bytes + +static void bench_strings_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + writer.encode_string(1, SHORT_STR, strlen(SHORT_STR)); + writer.encode_string(2, MEDIUM_STR, strlen(MEDIUM_STR)); + writer.encode_string(3, LONG_STR, strlen(LONG_STR)); +} + +static size_t calc_strings_size() { + uint32_t size = 0; + size += ProtoSize::calc_length(1, strlen(SHORT_STR)); + size += ProtoSize::calc_length(1, strlen(MEDIUM_STR)); + size += ProtoSize::calc_length(1, strlen(LONG_STR)); + return size; +} + +static void bench_strings_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_string(1, SHORT_STR, strlen(SHORT_STR)); + writer.encode_string(2, MEDIUM_STR, strlen(MEDIUM_STR)); + writer.encode_string(3, LONG_STR, strlen(LONG_STR)); +} + +// ============================================================================ +// Benchmark: Fixed32 encoding (simulates key fields in state responses) +// ============================================================================ + +static void bench_fixed32_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + for (uint32_t i = 1; i <= 10; i++) { + writer.encode_fixed32(i, 0xDEADBEEF); + } +} + +static size_t calc_fixed32_size() { + uint32_t size = 0; + for (uint32_t i = 1; i <= 10; i++) { + size += ProtoSize::calc_fixed32(1, 0xDEADBEEF); + } + return size; +} + +static void bench_fixed32_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + for (uint32_t i = 1; i <= 10; i++) { + writer.encode_fixed32(i, 0xDEADBEEF); + } +} + +// ============================================================================ +// Benchmark: Simulate SensorStateResponse encoding +// SensorStateResponse has: fixed32 key, float state, bool missing_state +// This is the most frequent message type during normal operation. +// ============================================================================ + +static void bench_sensor_state_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + writer.encode_fixed32(1, 0x12345678); // key + writer.encode_float(2, 23.5f); // state + writer.encode_bool(3, false); // missing_state (default, skipped) +} + +static size_t calc_sensor_state_size() { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, 0x12345678); + size += ProtoSize::calc_float(1, 23.5f); + size += ProtoSize::calc_bool(1, false); + return size; +} + +static void bench_sensor_state_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_fixed32(1, 0x12345678); + writer.encode_float(2, 23.5f); + writer.encode_bool(3, false); +} + +// ============================================================================ +// Benchmark: Simulate ListEntitiesSensorResponse encoding +// This is a larger message sent during entity listing. +// Fields: object_id, key, name, unique_id, icon, unit_of_measurement, +// accuracy_decimals, force_update, device_class, state_class +// ============================================================================ + +static const char OBJ_ID[] = "living_room_temp"; +static const char NAME[] = "Living Room Temperature"; +static const char UNIQUE_ID[] = "esp32_01-sensor-living_room_temp"; +static const char ICON[] = "mdi:thermometer"; +static const char UNIT[] = "\xc2\xb0" + "C"; // UTF-8 degree C +static const char DEVICE_CLASS[] = "temperature"; + +static void bench_list_entities_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + writer.encode_string(1, OBJ_ID, strlen(OBJ_ID)); // object_id + writer.encode_fixed32(2, 0xABCD1234); // key + writer.encode_string(3, NAME, strlen(NAME)); // name + writer.encode_string(4, UNIQUE_ID, strlen(UNIQUE_ID)); // unique_id + writer.encode_string(5, ICON, strlen(ICON)); // icon + writer.encode_string(6, UNIT, strlen(UNIT)); // unit_of_measurement + writer.encode_uint32(7, 1); // accuracy_decimals + writer.encode_bool(8, false); // force_update + writer.encode_string(9, DEVICE_CLASS, strlen(DEVICE_CLASS)); // device_class + writer.encode_uint32(10, 1); // state_class +} + +static size_t calc_list_entities_size() { + uint32_t size = 0; + size += ProtoSize::calc_length(1, strlen(OBJ_ID)); + size += ProtoSize::calc_fixed32(1, 0xABCD1234); + size += ProtoSize::calc_length(1, strlen(NAME)); + size += ProtoSize::calc_length(1, strlen(UNIQUE_ID)); + size += ProtoSize::calc_length(1, strlen(ICON)); + size += ProtoSize::calc_length(1, strlen(UNIT)); + size += ProtoSize::calc_uint32(1, 1); + size += ProtoSize::calc_bool(1, false); + size += ProtoSize::calc_length(1, strlen(DEVICE_CLASS)); + size += ProtoSize::calc_uint32(1, 1); + return size; +} + +static void bench_list_entities_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_string(1, OBJ_ID, strlen(OBJ_ID)); + writer.encode_fixed32(2, 0xABCD1234); + writer.encode_string(3, NAME, strlen(NAME)); + writer.encode_string(4, UNIQUE_ID, strlen(UNIQUE_ID)); + writer.encode_string(5, ICON, strlen(ICON)); + writer.encode_string(6, UNIT, strlen(UNIT)); + writer.encode_uint32(7, 1); + writer.encode_bool(8, false); + writer.encode_string(9, DEVICE_CLASS, strlen(DEVICE_CLASS)); + writer.encode_uint32(10, 1); +} + +// ============================================================================ +// Benchmark: Simulate BLE advertisement batch encoding +// BluetoothLERawAdvertisementsResponse with multiple advertisements. +// Each advert has: uint64 address, sint32 rssi, uint32 address_type, bytes data +// This is a high-frequency message that benefits most from optimization. +// ============================================================================ + +static const uint8_t FAKE_BLE_DATA[31] = {0x02, 0x01, 0x06, 0x11, 0x07, 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, + 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x03, + 0x09, 0x54, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00}; + +static void bench_ble_batch_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + // Simulate encoding 8 BLE advertisements + for (int i = 0; i < 8; i++) { + // Each advertisement fields (flattened, no nested message for simplicity) + writer.encode_uint32(1, static_cast(0xAABBCCDD + i)); // address (lower 32) + writer.encode_uint32(2, static_cast(-70 + i)); // rssi + writer.encode_uint32(3, 0); // address_type (public) + writer.encode_bytes(4, FAKE_BLE_DATA, sizeof(FAKE_BLE_DATA)); // data + } +} + +static size_t calc_ble_batch_size() { + uint32_t size = 0; + for (int i = 0; i < 8; i++) { + size += ProtoSize::calc_uint32(1, static_cast(0xAABBCCDD + i)); + size += ProtoSize::calc_uint32(1, static_cast(-70 + i)); + size += ProtoSize::calc_uint32(1, 0); + size += ProtoSize::calc_length(1, sizeof(FAKE_BLE_DATA)); + } + return size; +} + +static void bench_ble_batch_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + for (int i = 0; i < 8; i++) { + writer.encode_uint32(1, static_cast(0xAABBCCDD + i)); + writer.encode_uint32(2, static_cast(-70 + i)); + writer.encode_uint32(3, 0); + writer.encode_bytes(4, FAKE_BLE_DATA, sizeof(FAKE_BLE_DATA)); + } +} + +// ============================================================================ +// Benchmark: Simulate SubscribeLogsResponse encoding +// This is a frequent message: level (enum/uint32) + message (bytes) +// Message sizes vary from short to long log lines. +// ============================================================================ + +static const char LOG_SHORT[] = "[sensor:042]: 'Temperature': Sending state 23.50 °C"; +static const char LOG_LONG[] = "[wifi:042]: Connecting to 'MyNetwork'... [wifi:042]: Connected! " + "IP=192.168.1.100, SSID=MyNetwork, BSSID=AA:BB:CC:DD:EE:FF, Channel=6, RSSI=-42 dB"; + +static void bench_log_msg_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + writer.encode_uint32(1, 3); // level = DEBUG + writer.encode_bytes(3, reinterpret_cast(LOG_SHORT), strlen(LOG_SHORT)); +} + +static size_t calc_log_msg_size() { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, 3); + size += ProtoSize::calc_length(1, strlen(LOG_SHORT)); + return size; +} + +static void bench_log_msg_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_uint32(1, 3); + writer.encode_bytes(3, reinterpret_cast(LOG_SHORT), strlen(LOG_SHORT)); +} + +static void bench_log_long_old(std::vector &buf) { + buf.clear(); + OldProtoWriteBuffer writer(&buf); + writer.encode_uint32(1, 3); + writer.encode_bytes(3, reinterpret_cast(LOG_LONG), strlen(LOG_LONG)); +} + +static size_t calc_log_long_size() { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, 3); + size += ProtoSize::calc_length(1, strlen(LOG_LONG)); + return size; +} + +static void bench_log_long_new(std::vector &buf, size_t size) { + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_uint32(1, 3); + writer.encode_bytes(3, reinterpret_cast(LOG_LONG), strlen(LOG_LONG)); +} + +// ============================================================================ +// Benchmark: Full encode cycle including calculate_size + resize + encode +// This measures the realistic overhead of the pre-sizing approach. +// ============================================================================ + +static void bench_full_cycle_sensor_old(std::vector &buf) { + // Old approach: just encode directly (vector grows as needed) + buf.clear(); + buf.reserve(32); // Typical small reserve + OldProtoWriteBuffer writer(&buf); + writer.encode_fixed32(1, 0x12345678); + writer.encode_float(2, 23.5f); + writer.encode_bool(3, false); +} + +static void bench_full_cycle_sensor_new(std::vector &buf) { + // New approach: calculate size, resize, then encode + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, 0x12345678); + size += ProtoSize::calc_float(1, 23.5f); + size += ProtoSize::calc_bool(1, false); + + buf.clear(); + buf.resize(size); + NewProtoWriteBuffer writer(&buf, 0); + writer.encode_fixed32(1, 0x12345678); + writer.encode_float(2, 23.5f); + writer.encode_bool(3, false); +} + +// ============================================================================ +// Correctness verification +// ============================================================================ + +static bool verify_encoding_match() { + std::vector old_buf, new_buf; + bool all_pass = true; + + auto check = [&](const char *name) { + if (old_buf.size() != new_buf.size() || memcmp(old_buf.data(), new_buf.data(), old_buf.size()) != 0) { + printf("FAIL: %s - output mismatch (old=%zu bytes, new=%zu bytes)\n", name, old_buf.size(), new_buf.size()); + all_pass = false; + } + }; + + // Varint + bench_varint_old(old_buf); + bench_varint_new(new_buf, old_buf.size()); + check("varint"); + + // Strings + bench_strings_old(old_buf); + bench_strings_new(new_buf, calc_strings_size()); + check("strings"); + + // Fixed32 + bench_fixed32_old(old_buf); + bench_fixed32_new(new_buf, calc_fixed32_size()); + check("fixed32"); + + // SensorStateResponse + bench_sensor_state_old(old_buf); + bench_sensor_state_new(new_buf, calc_sensor_state_size()); + check("sensor_state"); + + // ListEntitiesSensorResponse + bench_list_entities_old(old_buf); + bench_list_entities_new(new_buf, calc_list_entities_size()); + check("list_entities"); + + // BLE batch + bench_ble_batch_old(old_buf); + bench_ble_batch_new(new_buf, calc_ble_batch_size()); + check("ble_batch"); + + // Log message + bench_log_msg_old(old_buf); + bench_log_msg_new(new_buf, calc_log_msg_size()); + check("log_short"); + + // Long log message + bench_log_long_old(old_buf); + bench_log_long_new(new_buf, calc_log_long_size()); + check("log_long"); + + return all_pass; +} + +// ============================================================================ +// Main +// ============================================================================ + +int main() { + printf("=== ProtoWriteBuffer Encoding Benchmark ===\n"); + printf("Comparing push_back() vs pre-sized pointer writes\n\n"); + + // Verify correctness first + printf("--- Correctness Verification ---\n"); + if (!verify_encoding_match()) { + printf("CORRECTNESS CHECK FAILED - encoding output differs!\n"); + return 1; + } + printf("All encoding outputs match between old and new implementations.\n\n"); + + // Calculate sizes for pre-allocation + size_t varint_size = 1 + 2 + 3 + 4 + 5; // 15 bytes + size_t strings_size = calc_strings_size(); + size_t fixed32_size = calc_fixed32_size(); + size_t sensor_state_size = calc_sensor_state_size(); + size_t list_entities_size = calc_list_entities_size(); + size_t ble_batch_size = calc_ble_batch_size(); + size_t log_msg_size = calc_log_msg_size(); + size_t log_long_size = calc_log_long_size(); + + std::vector buf; + buf.reserve(1024); // Pre-allocate to avoid measuring allocation + + std::vector results; + + // --- Varint encoding --- + printf("--- Running Benchmarks ---\n\n"); + + results.push_back(benchmark("varint_mix (old/push_back)", varint_size, [&] { bench_varint_old(buf); })); + results.push_back(benchmark("varint_mix (new/pointer)", varint_size, [&] { bench_varint_new(buf, varint_size); })); + + // --- String encoding --- + results.push_back(benchmark("strings_mix (old/push_back)", strings_size, [&] { bench_strings_old(buf); })); + results.push_back( + benchmark("strings_mix (new/pointer)", strings_size, [&] { bench_strings_new(buf, strings_size); })); + + // --- Fixed32 encoding --- + results.push_back(benchmark("fixed32_x10 (old/push_back)", fixed32_size, [&] { bench_fixed32_old(buf); })); + results.push_back( + benchmark("fixed32_x10 (new/pointer)", fixed32_size, [&] { bench_fixed32_new(buf, fixed32_size); })); + + // --- SensorStateResponse --- + results.push_back(benchmark("sensor_state (old/push_back)", sensor_state_size, [&] { bench_sensor_state_old(buf); })); + results.push_back(benchmark("sensor_state (new/pointer)", sensor_state_size, + [&] { bench_sensor_state_new(buf, sensor_state_size); })); + + // --- ListEntitiesSensorResponse --- + results.push_back( + benchmark("list_entities (old/push_back)", list_entities_size, [&] { bench_list_entities_old(buf); })); + results.push_back(benchmark("list_entities (new/pointer)", list_entities_size, + [&] { bench_list_entities_new(buf, list_entities_size); })); + + // --- BLE batch --- + results.push_back(benchmark("ble_batch_x8 (old/push_back)", ble_batch_size, [&] { bench_ble_batch_old(buf); })); + results.push_back( + benchmark("ble_batch_x8 (new/pointer)", ble_batch_size, [&] { bench_ble_batch_new(buf, ble_batch_size); })); + + // --- Log messages --- + results.push_back(benchmark("log_short (old/push_back)", log_msg_size, [&] { bench_log_msg_old(buf); })); + results.push_back(benchmark("log_short (new/pointer)", log_msg_size, [&] { bench_log_msg_new(buf, log_msg_size); })); + + results.push_back(benchmark("log_long (old/push_back)", log_long_size, [&] { bench_log_long_old(buf); })); + results.push_back( + benchmark("log_long (new/pointer)", log_long_size, [&] { bench_log_long_new(buf, log_long_size); })); + + // --- Full encode cycle (calculate_size + resize + encode) --- + results.push_back( + benchmark("full_cycle_sensor (old/push_back)", sensor_state_size, [&] { bench_full_cycle_sensor_old(buf); })); + results.push_back( + benchmark("full_cycle_sensor (new/pointer)", sensor_state_size, [&] { bench_full_cycle_sensor_new(buf); })); + + // Print all results + printf("\n--- Results ---\n\n"); + print_results(results); + + // Print comparison summary + printf("\n--- Speedup Summary (new vs old) ---\n\n"); + for (size_t i = 0; i + 1 < results.size(); i += 2) { + print_comparison(results[i].name, results[i], results[i + 1]); + } + + printf("\n--- Encoded Sizes ---\n\n"); + printf(" varint_mix: %3zu bytes\n", varint_size); + printf(" strings_mix: %3zu bytes\n", strings_size); + printf(" fixed32_x10: %3zu bytes\n", fixed32_size); + printf(" sensor_state: %3zu bytes\n", sensor_state_size); + printf(" list_entities: %3zu bytes\n", list_entities_size); + printf(" ble_batch_x8: %3zu bytes\n", ble_batch_size); + printf(" log_short: %3zu bytes\n", log_msg_size); + printf(" log_long: %3zu bytes\n", log_long_size); + + return 0; +} From 46c3a897fe79e307fb71efd12a557723a540e0b8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:27:02 -1000 Subject: [PATCH 22/42] Add benchmark comparing virtual vs direct dispatch for proto encoding --- tests/benchmarks/proto_message_benchmark.cpp | 783 +++++++++++++++++++ 1 file changed, 783 insertions(+) create mode 100644 tests/benchmarks/proto_message_benchmark.cpp diff --git a/tests/benchmarks/proto_message_benchmark.cpp b/tests/benchmarks/proto_message_benchmark.cpp new file mode 100644 index 00000000000..395cc4b8060 --- /dev/null +++ b/tests/benchmarks/proto_message_benchmark.cpp @@ -0,0 +1,783 @@ +/** + * Benchmark: Virtual dispatch vs direct calls for protobuf message encoding + * + * Compares: + * OLD: virtual dispatch for encode/calculate_size + ProtoSize accumulator object + * NEW: direct template calls for encode/calculate_size + static ProtoSize methods + * + * Build (from repo root): + * g++ -std=gnu++20 -O2 \ + * tests/benchmarks/proto_message_benchmark.cpp \ + * -o tests/benchmarks/proto_message_benchmark + * + * Run: + * ./tests/benchmarks/proto_message_benchmark + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================================ +// Benchmark infrastructure +// ============================================================================ + +struct BenchResult { + const char *name; + double ns_per_op; + double ops_per_sec; + size_t iterations; +}; + +template __attribute__((noinline)) void do_not_optimize(T &value) { + asm volatile("" : "+r,m"(value) : : "memory"); +} + +__attribute__((noinline)) void clobber_memory() { asm volatile("" : : : "memory"); } + +template BenchResult benchmark(const char *name, Func func) { + // Warmup + for (int i = 0; i < 1000; i++) { + func(); + } + + // Determine iteration count (target ~100ms) + size_t iterations = 1000; + auto start = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < iterations; i++) { + func(); + } + auto end = std::chrono::high_resolution_clock::now(); + double elapsed_ns = std::chrono::duration_cast(end - start).count(); + double ns_per_op = elapsed_ns / iterations; + + // Scale iterations to target ~500ms for stability + iterations = std::max(100000, static_cast(500'000'000.0 / ns_per_op)); + + // Actual benchmark run + start = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < iterations; i++) { + func(); + clobber_memory(); + } + end = std::chrono::high_resolution_clock::now(); + elapsed_ns = std::chrono::duration_cast(end - start).count(); + ns_per_op = elapsed_ns / iterations; + + return BenchResult{name, ns_per_op, 1'000'000'000.0 / ns_per_op, iterations}; +} + +void print_results(const std::vector &results) { + printf("%-55s %12s %15s %12s\n", "Benchmark", "ns/op", "ops/sec", "iters"); + printf("%-55s %12s %15s %12s\n", std::string(55, '-').c_str(), "--------", "--------", "--------"); + for (const auto &r : results) { + printf("%-55s %12.1f %15.0f %12zu\n", r.name, r.ns_per_op, r.ops_per_sec, r.iterations); + } +} + +void print_comparison(const char *label, const BenchResult &old_result, const BenchResult &new_result) { + double speedup = old_result.ns_per_op / new_result.ns_per_op; + const char *dir = speedup > 1.0 ? "faster" : "slower"; + printf(" %-51s %5.2fx %s\n", label, speedup > 1.0 ? speedup : 1.0 / speedup, dir); +} + +// ============================================================================ +// Shared encoding helpers (same for both old and new) +// ============================================================================ + +static constexpr uint32_t varint_size(uint32_t value) { + if (value < 128) + return 1; + if (value < 16384) + return 2; + if (value < 2097152) + return 3; + if (value < 268435456) + return 4; + return 5; +} + +class WriteBuffer { + public: + WriteBuffer(std::vector *buffer, size_t write_pos) : buffer_(buffer), pos_(buffer->data() + write_pos) {} + + void encode_varint_raw(uint32_t value) { + while (value > 0x7F) { + *this->pos_++ = static_cast(value | 0x80); + value >>= 7; + } + *this->pos_++ = static_cast(value); + } + + void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } + + void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { + if (len == 0 && !force) + return; + this->encode_field_raw(field_id, 2); + this->encode_varint_raw(len); + std::memcpy(this->pos_, string, len); + this->pos_ += len; + } + + void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 0); + this->encode_varint_raw(value); + } + + void encode_bool(uint32_t field_id, bool value, bool force = false) { + if (!value && !force) + return; + this->encode_field_raw(field_id, 0); + *this->pos_++ = value ? 0x01 : 0x00; + } + + void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { + if (value == 0 && !force) + return; + this->encode_field_raw(field_id, 5); + std::memcpy(this->pos_, &value, 4); + this->pos_ += 4; + } + + void encode_float(uint32_t field_id, float value, bool force = false) { + if (value == 0.0f && !force) + return; + union { + float value; + uint32_t raw; + } val{}; + val.value = value; + this->encode_fixed32(field_id, val.raw); + } + + void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { + this->encode_string(field_id, reinterpret_cast(data), len, force); + } + + // Nested message encoding (for old-style virtual dispatch) + void encode_message_virtual(uint32_t field_id, uint32_t nested_size, const void *value, + void (*encode_fn)(const void *, WriteBuffer &), bool force) { + if (nested_size == 0 && !force) + return; + this->encode_field_raw(field_id, 2); + this->encode_varint_raw(nested_size); + encode_fn(value, *this); + } + + // Nested message encoding (for new-style direct calls) + template void encode_message(uint32_t field_id, const T &value, bool force = true) { + uint32_t nested_size = value.calculate_size(); + if (nested_size == 0 && !force) + return; + this->encode_field_raw(field_id, 2); + this->encode_varint_raw(nested_size); + value.encode(*this); + } + + std::vector *buffer_; + uint8_t *pos_; +}; + +// ============================================================================ +// OLD approach: ProtoSize accumulator + virtual dispatch +// ============================================================================ + +namespace old_style { + +class ProtoSize { + public: + ProtoSize() = default; + uint32_t get_size() const { return total_size_; } + + void add_uint32(uint32_t field_id_size, uint32_t value) { + if (value != 0) + total_size_ += field_id_size + varint_size(value); + } + void add_bool(uint32_t field_id_size, bool value) { + if (value) + total_size_ += field_id_size + 1; + } + void add_float(uint32_t field_id_size, float value) { + if (value != 0.0f) + total_size_ += field_id_size + 4; + } + void add_fixed32(uint32_t field_id_size, uint32_t value) { + if (value != 0) + total_size_ += field_id_size + 4; + } + void add_length(uint32_t field_id_size, size_t len) { + if (len != 0) + total_size_ += field_id_size + varint_size(static_cast(len)) + static_cast(len); + } + void add_message_field_force(uint32_t field_id_size, uint32_t nested_size) { + total_size_ += field_id_size + varint_size(nested_size) + nested_size; + } + + private: + uint32_t total_size_ = 0; +}; + +class ProtoMessage { + public: + virtual void encode(WriteBuffer &buffer) const = 0; + virtual uint32_t calculate_size() const = 0; + virtual ~ProtoMessage() = default; +}; + +// Empty message (ping, disconnect, etc.) +class EmptyMessage : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 1; + void encode(WriteBuffer &buffer) const override {} + uint32_t calculate_size() const override { return 0; } +}; + +// SensorStateResponse: fixed32 key, float state, bool missing_state +class SensorStateResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 25; + uint32_t key{0x12345678}; + float state{23.5f}; + bool missing_state{false}; + + void encode(WriteBuffer &buffer) const override { + buffer.encode_fixed32(1, this->key); + buffer.encode_float(2, this->state); + buffer.encode_bool(3, this->missing_state); + } + + uint32_t calculate_size() const override { + ProtoSize size; + size.add_fixed32(1, this->key); + size.add_float(1, this->state); + size.add_bool(1, this->missing_state); + return size.get_size(); + } +}; + +// ListEntitiesSensorResponse: multiple strings + numeric fields +class ListEntitiesSensorResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 16; + std::string object_id{"living_room_temp"}; + uint32_t key{0xABCD1234}; + std::string name{"Living Room Temperature"}; + std::string unique_id{"esp32_01-sensor-living_room_temp"}; + std::string icon{"mdi:thermometer"}; + std::string unit_of_measurement{"\xc2\xb0" + "C"}; + uint32_t accuracy_decimals{1}; + bool force_update{false}; + std::string device_class{"temperature"}; + uint32_t state_class{1}; + + void encode(WriteBuffer &buffer) const override { + buffer.encode_string(1, this->object_id.data(), this->object_id.size()); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name.data(), this->name.size()); + buffer.encode_string(4, this->unique_id.data(), this->unique_id.size()); + buffer.encode_string(5, this->icon.data(), this->icon.size()); + buffer.encode_string(6, this->unit_of_measurement.data(), this->unit_of_measurement.size()); + buffer.encode_uint32(7, this->accuracy_decimals); + buffer.encode_bool(8, this->force_update); + buffer.encode_string(9, this->device_class.data(), this->device_class.size()); + buffer.encode_uint32(10, this->state_class); + } + + uint32_t calculate_size() const override { + ProtoSize size; + size.add_length(1, this->object_id.size()); + size.add_fixed32(1, this->key); + size.add_length(1, this->name.size()); + size.add_length(1, this->unique_id.size()); + size.add_length(1, this->icon.size()); + size.add_length(1, this->unit_of_measurement.size()); + size.add_uint32(1, this->accuracy_decimals); + size.add_bool(1, this->force_update); + size.add_length(1, this->device_class.size()); + size.add_uint32(1, this->state_class); + return size.get_size(); + } +}; + +// SubscribeLogsResponse: level + message bytes +class SubscribeLogsResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 29; + uint32_t level{3}; + std::string message{"[sensor:042]: 'Temperature': Sending state 23.50 C with 1 decimals of accuracy"}; + + void encode(WriteBuffer &buffer) const override { + buffer.encode_uint32(1, this->level); + buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); + } + + uint32_t calculate_size() const override { + ProtoSize size; + size.add_uint32(1, this->level); + size.add_length(1, this->message.size()); + return size.get_size(); + } +}; + +// Nested message: BluetoothGATTService with characteristics +class BluetoothGATTCharacteristic : public ProtoMessage { + public: + uint32_t uuid1{0x2A19}; + uint32_t handle{3}; + uint32_t properties{2}; + + void encode(WriteBuffer &buffer) const override { + buffer.encode_uint32(1, this->uuid1); + buffer.encode_uint32(2, this->handle); + buffer.encode_uint32(3, this->properties); + } + + uint32_t calculate_size() const override { + ProtoSize size; + size.add_uint32(1, this->uuid1); + size.add_uint32(1, this->handle); + size.add_uint32(1, this->properties); + return size.get_size(); + } +}; + +class BluetoothGATTService : public ProtoMessage { + public: + uint32_t uuid1{0x180F}; + uint32_t handle{1}; + std::vector characteristics; + + BluetoothGATTService() { characteristics.resize(4); } + + void encode(WriteBuffer &buffer) const override { + buffer.encode_uint32(1, this->uuid1); + buffer.encode_uint32(2, this->handle); + for (const auto &ch : this->characteristics) { + buffer.encode_message_virtual( + 3, ch.calculate_size(), &ch, + [](const void *msg, WriteBuffer &buf) { static_cast(msg)->encode(buf); }, + true); + } + } + + uint32_t calculate_size() const override { + ProtoSize size; + size.add_uint32(1, this->uuid1); + size.add_uint32(1, this->handle); + for (const auto &ch : this->characteristics) { + size.add_message_field_force(1, ch.calculate_size()); + } + return size.get_size(); + } +}; + +// send_message simulation: virtual dispatch through base pointer +__attribute__((noinline)) bool send_message(const ProtoMessage &msg, uint8_t msg_type, std::vector &buf) { + uint32_t size = msg.calculate_size(); + buf.resize(size); + WriteBuffer writer(&buf, 0); + msg.encode(writer); + do_not_optimize(buf); + return true; +} + +} // namespace old_style + +// ============================================================================ +// NEW approach: static ProtoSize + direct template calls +// ============================================================================ + +namespace new_style { + +class ProtoSize { + public: + static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + varint_size(value) : 0; + } + static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } + static constexpr uint32_t calc_float(uint32_t field_id_size, float value) { + return value != 0.0f ? field_id_size + 4 : 0; + } + static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + 4 : 0; + } + static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) { + return len ? field_id_size + varint_size(static_cast(len)) + static_cast(len) : 0; + } + static constexpr uint32_t calc_message_force(uint32_t field_id_size, uint32_t nested_size) { + return field_id_size + varint_size(nested_size) + nested_size; + } +}; + +class ProtoMessage { + public: + // Non-virtual defaults — concrete types hide these + void encode(WriteBuffer &buffer) const {} + uint32_t calculate_size() const { return 0; } + ~ProtoMessage() = default; +}; + +// Empty message +class EmptyMessage : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 1; + static constexpr uint32_t ESTIMATED_SIZE = 0; + void encode(WriteBuffer &buffer) const {} + uint32_t calculate_size() const { return 0; } +}; + +// SensorStateResponse +class SensorStateResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 25; + static constexpr uint32_t ESTIMATED_SIZE = 10; + uint32_t key{0x12345678}; + float state{23.5f}; + bool missing_state{false}; + + void encode(WriteBuffer &buffer) const { + buffer.encode_fixed32(1, this->key); + buffer.encode_float(2, this->state); + buffer.encode_bool(3, this->missing_state); + } + + uint32_t calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_float(1, this->state); + size += ProtoSize::calc_bool(1, this->missing_state); + return size; + } +}; + +// ListEntitiesSensorResponse +class ListEntitiesSensorResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 16; + static constexpr uint32_t ESTIMATED_SIZE = 128; + std::string object_id{"living_room_temp"}; + uint32_t key{0xABCD1234}; + std::string name{"Living Room Temperature"}; + std::string unique_id{"esp32_01-sensor-living_room_temp"}; + std::string icon{"mdi:thermometer"}; + std::string unit_of_measurement{"\xc2\xb0" + "C"}; + uint32_t accuracy_decimals{1}; + bool force_update{false}; + std::string device_class{"temperature"}; + uint32_t state_class{1}; + + void encode(WriteBuffer &buffer) const { + buffer.encode_string(1, this->object_id.data(), this->object_id.size()); + buffer.encode_fixed32(2, this->key); + buffer.encode_string(3, this->name.data(), this->name.size()); + buffer.encode_string(4, this->unique_id.data(), this->unique_id.size()); + buffer.encode_string(5, this->icon.data(), this->icon.size()); + buffer.encode_string(6, this->unit_of_measurement.data(), this->unit_of_measurement.size()); + buffer.encode_uint32(7, this->accuracy_decimals); + buffer.encode_bool(8, this->force_update); + buffer.encode_string(9, this->device_class.data(), this->device_class.size()); + buffer.encode_uint32(10, this->state_class); + } + + uint32_t calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_length(1, this->object_id.size()); + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->name.size()); + size += ProtoSize::calc_length(1, this->unique_id.size()); + size += ProtoSize::calc_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); + size += ProtoSize::calc_uint32(1, this->accuracy_decimals); + size += ProtoSize::calc_bool(1, this->force_update); + size += ProtoSize::calc_length(1, this->device_class.size()); + size += ProtoSize::calc_uint32(1, this->state_class); + return size; + } +}; + +// SubscribeLogsResponse +class SubscribeLogsResponse : public ProtoMessage { + public: + static constexpr uint8_t MESSAGE_TYPE = 29; + static constexpr uint32_t ESTIMATED_SIZE = 80; + uint32_t level{3}; + std::string message{"[sensor:042]: 'Temperature': Sending state 23.50 C with 1 decimals of accuracy"}; + + void encode(WriteBuffer &buffer) const { + buffer.encode_uint32(1, this->level); + buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); + } + + uint32_t calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, this->level); + size += ProtoSize::calc_length(1, this->message.size()); + return size; + } +}; + +// Nested: BluetoothGATTCharacteristic +class BluetoothGATTCharacteristic : public ProtoMessage { + public: + static constexpr uint32_t ESTIMATED_SIZE = 10; + uint32_t uuid1{0x2A19}; + uint32_t handle{3}; + uint32_t properties{2}; + + void encode(WriteBuffer &buffer) const { + buffer.encode_uint32(1, this->uuid1); + buffer.encode_uint32(2, this->handle); + buffer.encode_uint32(3, this->properties); + } + + uint32_t calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, this->uuid1); + size += ProtoSize::calc_uint32(1, this->handle); + size += ProtoSize::calc_uint32(1, this->properties); + return size; + } +}; + +// Nested: BluetoothGATTService +class BluetoothGATTService : public ProtoMessage { + public: + static constexpr uint32_t ESTIMATED_SIZE = 64; + uint32_t uuid1{0x180F}; + uint32_t handle{1}; + std::vector characteristics; + + BluetoothGATTService() { characteristics.resize(4); } + + void encode(WriteBuffer &buffer) const { + buffer.encode_uint32(1, this->uuid1); + buffer.encode_uint32(2, this->handle); + for (const auto &ch : this->characteristics) { + buffer.encode_message(3, ch, true); + } + } + + uint32_t calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, this->uuid1); + size += ProtoSize::calc_uint32(1, this->handle); + for (const auto &ch : this->characteristics) { + size += ProtoSize::calc_message_force(1, ch.calculate_size()); + } + return size; + } +}; + +// Encode thunk for non-template core +template void encode_msg(const void *msg, WriteBuffer &buf) { static_cast(msg)->encode(buf); } + +static void encode_msg_noop(const void *, WriteBuffer &) {} + +// send_message template: direct calls, no virtual dispatch +template __attribute__((noinline)) bool send_message(const T &msg, std::vector &buf) { + uint32_t size; + void (*encode_fn)(const void *, WriteBuffer &); + if constexpr (T::ESTIMATED_SIZE == 0) { + size = 0; + encode_fn = &encode_msg_noop; + } else { + size = msg.calculate_size(); + encode_fn = &encode_msg; + } + buf.resize(size); + WriteBuffer writer(&buf, 0); + encode_fn(&msg, writer); + do_not_optimize(buf); + return true; +} + +} // namespace new_style + +// ============================================================================ +// Correctness verification +// ============================================================================ + +static bool verify_correctness() { + std::vector old_buf, new_buf; + bool all_pass = true; + + auto check = [&](const char *name) { + if (old_buf.size() != new_buf.size() || + (old_buf.size() > 0 && memcmp(old_buf.data(), new_buf.data(), old_buf.size()) != 0)) { + printf("FAIL: %s - output mismatch (old=%zu bytes, new=%zu bytes)\n", name, old_buf.size(), new_buf.size()); + all_pass = false; + } else { + printf(" OK: %s (%zu bytes)\n", name, old_buf.size()); + } + }; + + // Empty + { + old_style::EmptyMessage old_msg; + new_style::EmptyMessage new_msg; + old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); + new_style::send_message(new_msg, new_buf); + check("EmptyMessage"); + } + // SensorState + { + old_style::SensorStateResponse old_msg; + new_style::SensorStateResponse new_msg; + old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); + new_style::send_message(new_msg, new_buf); + check("SensorStateResponse"); + } + // ListEntities + { + old_style::ListEntitiesSensorResponse old_msg; + new_style::ListEntitiesSensorResponse new_msg; + old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); + new_style::send_message(new_msg, new_buf); + check("ListEntitiesSensorResponse"); + } + // Log + { + old_style::SubscribeLogsResponse old_msg; + new_style::SubscribeLogsResponse new_msg; + old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); + new_style::send_message(new_msg, new_buf); + check("SubscribeLogsResponse"); + } + // Nested (GATT service) + { + old_style::BluetoothGATTService old_msg; + new_style::BluetoothGATTService new_msg; + old_style::send_message(old_msg, 7, old_buf); + new_style::send_message(new_msg, new_buf); + check("BluetoothGATTService (nested)"); + } + + return all_pass; +} + +// ============================================================================ +// Benchmark: calculate_size only +// ============================================================================ + +template __attribute__((noinline)) uint32_t bench_calc_size_virtual(const T &msg) { + // Force virtual dispatch by going through base pointer + const old_style::ProtoMessage *base = &msg; + uint32_t s = base->calculate_size(); + do_not_optimize(s); + return s; +} + +template __attribute__((noinline)) uint32_t bench_calc_size_direct(const T &msg) { + uint32_t s = msg.calculate_size(); + do_not_optimize(s); + return s; +} + +// ============================================================================ +// Main +// ============================================================================ + +int main() { + printf("=== Proto Message Encoding Benchmark ===\n"); + printf("Comparing virtual dispatch + accumulator ProtoSize vs direct calls + static ProtoSize\n\n"); + + // Verify correctness + printf("--- Correctness Verification ---\n"); + if (!verify_correctness()) { + printf("\nCORRECTNESS CHECK FAILED!\n"); + return 1; + } + printf("All outputs match.\n\n"); + + std::vector buf; + buf.reserve(1024); + + std::vector results; + + // ---- calculate_size benchmarks ---- + printf("--- Running calculate_size Benchmarks ---\n\n"); + + { + old_style::SensorStateResponse old_msg; + new_style::SensorStateResponse new_msg; + results.push_back(benchmark("calc_size: SensorState (virtual)", [&] { bench_calc_size_virtual(old_msg); })); + results.push_back(benchmark("calc_size: SensorState (direct+static)", [&] { bench_calc_size_direct(new_msg); })); + } + { + old_style::ListEntitiesSensorResponse old_msg; + new_style::ListEntitiesSensorResponse new_msg; + results.push_back(benchmark("calc_size: ListEntities (virtual)", [&] { bench_calc_size_virtual(old_msg); })); + results.push_back(benchmark("calc_size: ListEntities (direct+static)", [&] { bench_calc_size_direct(new_msg); })); + } + { + old_style::SubscribeLogsResponse old_msg; + new_style::SubscribeLogsResponse new_msg; + results.push_back(benchmark("calc_size: LogResponse (virtual)", [&] { bench_calc_size_virtual(old_msg); })); + results.push_back(benchmark("calc_size: LogResponse (direct+static)", [&] { bench_calc_size_direct(new_msg); })); + } + { + old_style::BluetoothGATTService old_msg; + new_style::BluetoothGATTService new_msg; + results.push_back(benchmark("calc_size: GATTService/nested (virtual)", [&] { bench_calc_size_virtual(old_msg); })); + results.push_back( + benchmark("calc_size: GATTService/nested (direct+static)", [&] { bench_calc_size_direct(new_msg); })); + } + + // ---- Full send_message benchmarks ---- + printf("--- Running send_message Benchmarks ---\n\n"); + + { + old_style::EmptyMessage old_msg; + new_style::EmptyMessage new_msg; + results.push_back(benchmark("send: EmptyMessage (virtual)", [&] { old_style::send_message(old_msg, 1, buf); })); + results.push_back(benchmark("send: EmptyMessage (direct+static)", [&] { new_style::send_message(new_msg, buf); })); + } + { + old_style::SensorStateResponse old_msg; + new_style::SensorStateResponse new_msg; + results.push_back(benchmark("send: SensorState (virtual)", [&] { old_style::send_message(old_msg, 25, buf); })); + results.push_back(benchmark("send: SensorState (direct+static)", [&] { new_style::send_message(new_msg, buf); })); + } + { + old_style::ListEntitiesSensorResponse old_msg; + new_style::ListEntitiesSensorResponse new_msg; + results.push_back(benchmark("send: ListEntities (virtual)", [&] { old_style::send_message(old_msg, 16, buf); })); + results.push_back(benchmark("send: ListEntities (direct+static)", [&] { new_style::send_message(new_msg, buf); })); + } + { + old_style::SubscribeLogsResponse old_msg; + new_style::SubscribeLogsResponse new_msg; + results.push_back(benchmark("send: LogResponse (virtual)", [&] { old_style::send_message(old_msg, 29, buf); })); + results.push_back(benchmark("send: LogResponse (direct+static)", [&] { new_style::send_message(new_msg, buf); })); + } + { + old_style::BluetoothGATTService old_msg; + new_style::BluetoothGATTService new_msg; + results.push_back( + benchmark("send: GATTService/nested (virtual)", [&] { old_style::send_message(old_msg, 7, buf); })); + results.push_back( + benchmark("send: GATTService/nested (direct+static)", [&] { new_style::send_message(new_msg, buf); })); + } + + // Print all results + printf("\n--- Results ---\n\n"); + print_results(results); + + // Print comparison summary + printf("\n--- Speedup Summary (new vs old) ---\n\n"); + for (size_t i = 0; i + 1 < results.size(); i += 2) { + print_comparison(results[i].name, results[i], results[i + 1]); + } + + return 0; +} From 3548911b071b62d8a693884a1d527eb9745c7841 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 20:45:36 -1000 Subject: [PATCH 23/42] cleanup --- tests/benchmarks/proto_encode_benchmark.cpp | 795 ------------------- tests/benchmarks/proto_message_benchmark.cpp | 783 ------------------ 2 files changed, 1578 deletions(-) delete mode 100644 tests/benchmarks/proto_encode_benchmark.cpp delete mode 100644 tests/benchmarks/proto_message_benchmark.cpp diff --git a/tests/benchmarks/proto_encode_benchmark.cpp b/tests/benchmarks/proto_encode_benchmark.cpp deleted file mode 100644 index ac49e139aec..00000000000 --- a/tests/benchmarks/proto_encode_benchmark.cpp +++ /dev/null @@ -1,795 +0,0 @@ -/** - * Benchmark: ProtoWriteBuffer encoding performance - * - * Compares the old push_back()-based encoding against the new pre-sized - * pointer-write approach introduced in PR #14018. - * - * Build (from repo root): - * g++ -std=gnu++20 -O2 \ - * tests/benchmarks/proto_encode_benchmark.cpp \ - * -o tests/benchmarks/proto_encode_benchmark - * - * For ESP-like size-optimized builds (-Os): - * g++ -std=gnu++20 -Os \ - * tests/benchmarks/proto_encode_benchmark.cpp \ - * -o tests/benchmarks/proto_encode_benchmark - * - * Run: - * ./tests/benchmarks/proto_encode_benchmark - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// ============================================================================ -// Minimal stubs to avoid pulling in the full ESPHome framework -// ============================================================================ - -namespace esphome { - -class StringRef { - public: - constexpr StringRef() : base_(""), len_(0) {} - explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {} - constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {} - explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {} - - const char *c_str() const { return base_; } - size_t size() const { return len_; } - bool empty() const { return len_ == 0; } - - private: - const char *base_; - size_t len_; -}; - -} // namespace esphome - -// ============================================================================ -// Old-style ProtoWriteBuffer (push_back based) - from dev branch -// ============================================================================ - -class OldProtoWriteBuffer { - public: - explicit OldProtoWriteBuffer(std::vector *buffer) : buffer_(buffer) {} - - void encode_varint_raw(uint32_t value) { - while (value > 0x7F) { - this->buffer_->push_back(static_cast(value | 0x80)); - value >>= 7; - } - this->buffer_->push_back(static_cast(value)); - } - - void encode_varint_raw_64(uint64_t value) { - while (value > 0x7F) { - this->buffer_->push_back(static_cast(value | 0x80)); - value >>= 7; - } - this->buffer_->push_back(static_cast(value)); - } - - void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } - - void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { - if (len == 0 && !force) - return; - this->encode_field_raw(field_id, 2); - this->encode_varint_raw(len); - size_t old_size = this->buffer_->size(); - this->buffer_->resize(old_size + len); - std::memcpy(this->buffer_->data() + old_size, string, len); - } - - void encode_string(uint32_t field_id, const esphome::StringRef &ref, bool force = false) { - this->encode_string(field_id, ref.c_str(), ref.size(), force); - } - - void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 0); - this->encode_varint_raw(value); - } - - void encode_bool(uint32_t field_id, bool value, bool force = false) { - if (!value && !force) - return; - this->encode_field_raw(field_id, 0); - this->buffer_->push_back(value ? 0x01 : 0x00); - } - - void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 5); - this->buffer_->push_back((value >> 0) & 0xFF); - this->buffer_->push_back((value >> 8) & 0xFF); - this->buffer_->push_back((value >> 16) & 0xFF); - this->buffer_->push_back((value >> 24) & 0xFF); - } - - void encode_float(uint32_t field_id, float value, bool force = false) { - if (value == 0.0f && !force) - return; - union { - float value; - uint32_t raw; - } val{}; - val.value = value; - this->encode_fixed32(field_id, val.raw); - } - - void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { - this->encode_string(field_id, reinterpret_cast(data), len, force); - } - - std::vector *get_buffer() const { return buffer_; } - - protected: - std::vector *buffer_; -}; - -// ============================================================================ -// New-style ProtoWriteBuffer (pointer-write based) - from this PR -// ============================================================================ - -class NewProtoWriteBuffer { - public: - NewProtoWriteBuffer(std::vector *buffer, size_t write_pos) - : buffer_(buffer), pos_(buffer->data() + write_pos) {} - - void encode_varint_raw(uint32_t value) { - while (value > 0x7F) { - *this->pos_++ = static_cast(value | 0x80); - value >>= 7; - } - *this->pos_++ = static_cast(value); - } - - void encode_varint_raw_64(uint64_t value) { - while (value > 0x7F) { - *this->pos_++ = static_cast(value | 0x80); - value >>= 7; - } - *this->pos_++ = static_cast(value); - } - - void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } - - void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { - if (len == 0 && !force) - return; - this->encode_field_raw(field_id, 2); - this->encode_varint_raw(len); - std::memcpy(this->pos_, string, len); - this->pos_ += len; - } - - void encode_string(uint32_t field_id, const esphome::StringRef &ref, bool force = false) { - this->encode_string(field_id, ref.c_str(), ref.size(), force); - } - - void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 0); - this->encode_varint_raw(value); - } - - void encode_bool(uint32_t field_id, bool value, bool force = false) { - if (!value && !force) - return; - this->encode_field_raw(field_id, 0); - *this->pos_++ = value ? 0x01 : 0x00; - } - - void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 5); -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::memcpy(this->pos_, &value, 4); - this->pos_ += 4; -#else - *this->pos_++ = (value >> 0) & 0xFF; - *this->pos_++ = (value >> 8) & 0xFF; - *this->pos_++ = (value >> 16) & 0xFF; - *this->pos_++ = (value >> 24) & 0xFF; -#endif - } - - void encode_float(uint32_t field_id, float value, bool force = false) { - if (value == 0.0f && !force) - return; - union { - float value; - uint32_t raw; - } val{}; - val.value = value; - this->encode_fixed32(field_id, val.raw); - } - - void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { - this->encode_string(field_id, reinterpret_cast(data), len, force); - } - - uint8_t *pos() const { return pos_; } - std::vector *get_buffer() const { return buffer_; } - - protected: - std::vector *buffer_; - uint8_t *pos_; -}; - -// ============================================================================ -// ProtoSize - calculate exact encoded size (shared by both approaches) -// ============================================================================ - -class ProtoSize { - public: - static constexpr uint32_t varint(uint32_t value) { - if (value < 128) - return 1; - if (value < 16384) - return 2; - if (value < 2097152) - return 3; - if (value < 268435456) - return 4; - return 5; - } - - static constexpr uint32_t field(uint32_t field_id, uint32_t type) { return varint((field_id << 3) | (type & 0x7)); } - - static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value) { - return value ? field_id_size + varint(value) : 0; - } - - static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } - - static constexpr uint32_t calc_float(uint32_t field_id_size, float value) { - return value != 0.0f ? field_id_size + 4 : 0; - } - - static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value) { - return value ? field_id_size + 4 : 0; - } - - static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) { - return len ? field_id_size + varint(static_cast(len)) + static_cast(len) : 0; - } -}; - -// ============================================================================ -// Benchmark infrastructure -// ============================================================================ - -struct BenchResult { - const char *name; - double ns_per_op; - double ops_per_sec; - size_t iterations; - size_t bytes_per_op; -}; - -// Prevent compiler from optimizing away the result -template __attribute__((noinline)) void do_not_optimize(T &value) { - asm volatile("" : "+r,m"(value) : : "memory"); -} - -__attribute__((noinline)) void clobber_memory() { asm volatile("" : : : "memory"); } - -template BenchResult benchmark(const char *name, size_t bytes_per_op, Func func) { - // Warmup - for (int i = 0; i < 1000; i++) { - func(); - } - - // Determine iteration count (target ~100ms) - size_t iterations = 1000; - auto start = std::chrono::high_resolution_clock::now(); - for (size_t i = 0; i < iterations; i++) { - func(); - } - auto end = std::chrono::high_resolution_clock::now(); - double elapsed_ns = std::chrono::duration_cast(end - start).count(); - double ns_per_op = elapsed_ns / iterations; - - // Scale iterations to target ~200ms - iterations = std::max(10000, static_cast(200'000'000.0 / ns_per_op)); - - // Actual benchmark run - start = std::chrono::high_resolution_clock::now(); - for (size_t i = 0; i < iterations; i++) { - func(); - clobber_memory(); - } - end = std::chrono::high_resolution_clock::now(); - elapsed_ns = std::chrono::duration_cast(end - start).count(); - ns_per_op = elapsed_ns / iterations; - - return BenchResult{name, ns_per_op, 1'000'000'000.0 / ns_per_op, iterations, bytes_per_op}; -} - -void print_results(const std::vector &results) { - printf("%-50s %12s %12s %12s %10s\n", "Benchmark", "ns/op", "ops/sec", "iters", "bytes/op"); - printf("%-50s %12s %12s %12s %10s\n", std::string(50, '-').c_str(), "--------", "--------", "--------", "--------"); - for (const auto &r : results) { - printf("%-50s %12.1f %12.0f %12zu %10zu\n", r.name, r.ns_per_op, r.ops_per_sec, r.iterations, r.bytes_per_op); - } -} - -void print_comparison(const char *label, const BenchResult &old_result, const BenchResult &new_result) { - double speedup = old_result.ns_per_op / new_result.ns_per_op; - printf(" %-46s %.1fx %s\n", label, speedup, speedup > 1.0 ? "faster" : "slower"); -} - -// ============================================================================ -// Benchmark: Varint encoding -// ============================================================================ - -static void bench_varint_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - // Encode a mix of varint sizes (1-5 bytes) - writer.encode_varint_raw(0x01); // 1 byte - writer.encode_varint_raw(0x80); // 2 bytes - writer.encode_varint_raw(0x4000); // 3 bytes - writer.encode_varint_raw(0x200000); // 4 bytes - writer.encode_varint_raw(0x10000000); // 5 bytes -} - -static void bench_varint_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_varint_raw(0x01); - writer.encode_varint_raw(0x80); - writer.encode_varint_raw(0x4000); - writer.encode_varint_raw(0x200000); - writer.encode_varint_raw(0x10000000); -} - -// ============================================================================ -// Benchmark: String encoding (simulates entity names, object_ids, etc.) -// ============================================================================ - -static const char SHORT_STR[] = "sensor_1"; // 8 bytes -static const char MEDIUM_STR[] = "living_room_temperature_sensor"; // 30 bytes -static const char LONG_STR[] = - "esphome_very_long_device_name_with_many_characters_for_testing_purposes_abcdef"; // 78 bytes - -static void bench_strings_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - writer.encode_string(1, SHORT_STR, strlen(SHORT_STR)); - writer.encode_string(2, MEDIUM_STR, strlen(MEDIUM_STR)); - writer.encode_string(3, LONG_STR, strlen(LONG_STR)); -} - -static size_t calc_strings_size() { - uint32_t size = 0; - size += ProtoSize::calc_length(1, strlen(SHORT_STR)); - size += ProtoSize::calc_length(1, strlen(MEDIUM_STR)); - size += ProtoSize::calc_length(1, strlen(LONG_STR)); - return size; -} - -static void bench_strings_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_string(1, SHORT_STR, strlen(SHORT_STR)); - writer.encode_string(2, MEDIUM_STR, strlen(MEDIUM_STR)); - writer.encode_string(3, LONG_STR, strlen(LONG_STR)); -} - -// ============================================================================ -// Benchmark: Fixed32 encoding (simulates key fields in state responses) -// ============================================================================ - -static void bench_fixed32_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - for (uint32_t i = 1; i <= 10; i++) { - writer.encode_fixed32(i, 0xDEADBEEF); - } -} - -static size_t calc_fixed32_size() { - uint32_t size = 0; - for (uint32_t i = 1; i <= 10; i++) { - size += ProtoSize::calc_fixed32(1, 0xDEADBEEF); - } - return size; -} - -static void bench_fixed32_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - for (uint32_t i = 1; i <= 10; i++) { - writer.encode_fixed32(i, 0xDEADBEEF); - } -} - -// ============================================================================ -// Benchmark: Simulate SensorStateResponse encoding -// SensorStateResponse has: fixed32 key, float state, bool missing_state -// This is the most frequent message type during normal operation. -// ============================================================================ - -static void bench_sensor_state_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - writer.encode_fixed32(1, 0x12345678); // key - writer.encode_float(2, 23.5f); // state - writer.encode_bool(3, false); // missing_state (default, skipped) -} - -static size_t calc_sensor_state_size() { - uint32_t size = 0; - size += ProtoSize::calc_fixed32(1, 0x12345678); - size += ProtoSize::calc_float(1, 23.5f); - size += ProtoSize::calc_bool(1, false); - return size; -} - -static void bench_sensor_state_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_fixed32(1, 0x12345678); - writer.encode_float(2, 23.5f); - writer.encode_bool(3, false); -} - -// ============================================================================ -// Benchmark: Simulate ListEntitiesSensorResponse encoding -// This is a larger message sent during entity listing. -// Fields: object_id, key, name, unique_id, icon, unit_of_measurement, -// accuracy_decimals, force_update, device_class, state_class -// ============================================================================ - -static const char OBJ_ID[] = "living_room_temp"; -static const char NAME[] = "Living Room Temperature"; -static const char UNIQUE_ID[] = "esp32_01-sensor-living_room_temp"; -static const char ICON[] = "mdi:thermometer"; -static const char UNIT[] = "\xc2\xb0" - "C"; // UTF-8 degree C -static const char DEVICE_CLASS[] = "temperature"; - -static void bench_list_entities_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - writer.encode_string(1, OBJ_ID, strlen(OBJ_ID)); // object_id - writer.encode_fixed32(2, 0xABCD1234); // key - writer.encode_string(3, NAME, strlen(NAME)); // name - writer.encode_string(4, UNIQUE_ID, strlen(UNIQUE_ID)); // unique_id - writer.encode_string(5, ICON, strlen(ICON)); // icon - writer.encode_string(6, UNIT, strlen(UNIT)); // unit_of_measurement - writer.encode_uint32(7, 1); // accuracy_decimals - writer.encode_bool(8, false); // force_update - writer.encode_string(9, DEVICE_CLASS, strlen(DEVICE_CLASS)); // device_class - writer.encode_uint32(10, 1); // state_class -} - -static size_t calc_list_entities_size() { - uint32_t size = 0; - size += ProtoSize::calc_length(1, strlen(OBJ_ID)); - size += ProtoSize::calc_fixed32(1, 0xABCD1234); - size += ProtoSize::calc_length(1, strlen(NAME)); - size += ProtoSize::calc_length(1, strlen(UNIQUE_ID)); - size += ProtoSize::calc_length(1, strlen(ICON)); - size += ProtoSize::calc_length(1, strlen(UNIT)); - size += ProtoSize::calc_uint32(1, 1); - size += ProtoSize::calc_bool(1, false); - size += ProtoSize::calc_length(1, strlen(DEVICE_CLASS)); - size += ProtoSize::calc_uint32(1, 1); - return size; -} - -static void bench_list_entities_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_string(1, OBJ_ID, strlen(OBJ_ID)); - writer.encode_fixed32(2, 0xABCD1234); - writer.encode_string(3, NAME, strlen(NAME)); - writer.encode_string(4, UNIQUE_ID, strlen(UNIQUE_ID)); - writer.encode_string(5, ICON, strlen(ICON)); - writer.encode_string(6, UNIT, strlen(UNIT)); - writer.encode_uint32(7, 1); - writer.encode_bool(8, false); - writer.encode_string(9, DEVICE_CLASS, strlen(DEVICE_CLASS)); - writer.encode_uint32(10, 1); -} - -// ============================================================================ -// Benchmark: Simulate BLE advertisement batch encoding -// BluetoothLERawAdvertisementsResponse with multiple advertisements. -// Each advert has: uint64 address, sint32 rssi, uint32 address_type, bytes data -// This is a high-frequency message that benefits most from optimization. -// ============================================================================ - -static const uint8_t FAKE_BLE_DATA[31] = {0x02, 0x01, 0x06, 0x11, 0x07, 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, - 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x03, - 0x09, 0x54, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00}; - -static void bench_ble_batch_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - // Simulate encoding 8 BLE advertisements - for (int i = 0; i < 8; i++) { - // Each advertisement fields (flattened, no nested message for simplicity) - writer.encode_uint32(1, static_cast(0xAABBCCDD + i)); // address (lower 32) - writer.encode_uint32(2, static_cast(-70 + i)); // rssi - writer.encode_uint32(3, 0); // address_type (public) - writer.encode_bytes(4, FAKE_BLE_DATA, sizeof(FAKE_BLE_DATA)); // data - } -} - -static size_t calc_ble_batch_size() { - uint32_t size = 0; - for (int i = 0; i < 8; i++) { - size += ProtoSize::calc_uint32(1, static_cast(0xAABBCCDD + i)); - size += ProtoSize::calc_uint32(1, static_cast(-70 + i)); - size += ProtoSize::calc_uint32(1, 0); - size += ProtoSize::calc_length(1, sizeof(FAKE_BLE_DATA)); - } - return size; -} - -static void bench_ble_batch_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - for (int i = 0; i < 8; i++) { - writer.encode_uint32(1, static_cast(0xAABBCCDD + i)); - writer.encode_uint32(2, static_cast(-70 + i)); - writer.encode_uint32(3, 0); - writer.encode_bytes(4, FAKE_BLE_DATA, sizeof(FAKE_BLE_DATA)); - } -} - -// ============================================================================ -// Benchmark: Simulate SubscribeLogsResponse encoding -// This is a frequent message: level (enum/uint32) + message (bytes) -// Message sizes vary from short to long log lines. -// ============================================================================ - -static const char LOG_SHORT[] = "[sensor:042]: 'Temperature': Sending state 23.50 °C"; -static const char LOG_LONG[] = "[wifi:042]: Connecting to 'MyNetwork'... [wifi:042]: Connected! " - "IP=192.168.1.100, SSID=MyNetwork, BSSID=AA:BB:CC:DD:EE:FF, Channel=6, RSSI=-42 dB"; - -static void bench_log_msg_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - writer.encode_uint32(1, 3); // level = DEBUG - writer.encode_bytes(3, reinterpret_cast(LOG_SHORT), strlen(LOG_SHORT)); -} - -static size_t calc_log_msg_size() { - uint32_t size = 0; - size += ProtoSize::calc_uint32(1, 3); - size += ProtoSize::calc_length(1, strlen(LOG_SHORT)); - return size; -} - -static void bench_log_msg_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_uint32(1, 3); - writer.encode_bytes(3, reinterpret_cast(LOG_SHORT), strlen(LOG_SHORT)); -} - -static void bench_log_long_old(std::vector &buf) { - buf.clear(); - OldProtoWriteBuffer writer(&buf); - writer.encode_uint32(1, 3); - writer.encode_bytes(3, reinterpret_cast(LOG_LONG), strlen(LOG_LONG)); -} - -static size_t calc_log_long_size() { - uint32_t size = 0; - size += ProtoSize::calc_uint32(1, 3); - size += ProtoSize::calc_length(1, strlen(LOG_LONG)); - return size; -} - -static void bench_log_long_new(std::vector &buf, size_t size) { - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_uint32(1, 3); - writer.encode_bytes(3, reinterpret_cast(LOG_LONG), strlen(LOG_LONG)); -} - -// ============================================================================ -// Benchmark: Full encode cycle including calculate_size + resize + encode -// This measures the realistic overhead of the pre-sizing approach. -// ============================================================================ - -static void bench_full_cycle_sensor_old(std::vector &buf) { - // Old approach: just encode directly (vector grows as needed) - buf.clear(); - buf.reserve(32); // Typical small reserve - OldProtoWriteBuffer writer(&buf); - writer.encode_fixed32(1, 0x12345678); - writer.encode_float(2, 23.5f); - writer.encode_bool(3, false); -} - -static void bench_full_cycle_sensor_new(std::vector &buf) { - // New approach: calculate size, resize, then encode - uint32_t size = 0; - size += ProtoSize::calc_fixed32(1, 0x12345678); - size += ProtoSize::calc_float(1, 23.5f); - size += ProtoSize::calc_bool(1, false); - - buf.clear(); - buf.resize(size); - NewProtoWriteBuffer writer(&buf, 0); - writer.encode_fixed32(1, 0x12345678); - writer.encode_float(2, 23.5f); - writer.encode_bool(3, false); -} - -// ============================================================================ -// Correctness verification -// ============================================================================ - -static bool verify_encoding_match() { - std::vector old_buf, new_buf; - bool all_pass = true; - - auto check = [&](const char *name) { - if (old_buf.size() != new_buf.size() || memcmp(old_buf.data(), new_buf.data(), old_buf.size()) != 0) { - printf("FAIL: %s - output mismatch (old=%zu bytes, new=%zu bytes)\n", name, old_buf.size(), new_buf.size()); - all_pass = false; - } - }; - - // Varint - bench_varint_old(old_buf); - bench_varint_new(new_buf, old_buf.size()); - check("varint"); - - // Strings - bench_strings_old(old_buf); - bench_strings_new(new_buf, calc_strings_size()); - check("strings"); - - // Fixed32 - bench_fixed32_old(old_buf); - bench_fixed32_new(new_buf, calc_fixed32_size()); - check("fixed32"); - - // SensorStateResponse - bench_sensor_state_old(old_buf); - bench_sensor_state_new(new_buf, calc_sensor_state_size()); - check("sensor_state"); - - // ListEntitiesSensorResponse - bench_list_entities_old(old_buf); - bench_list_entities_new(new_buf, calc_list_entities_size()); - check("list_entities"); - - // BLE batch - bench_ble_batch_old(old_buf); - bench_ble_batch_new(new_buf, calc_ble_batch_size()); - check("ble_batch"); - - // Log message - bench_log_msg_old(old_buf); - bench_log_msg_new(new_buf, calc_log_msg_size()); - check("log_short"); - - // Long log message - bench_log_long_old(old_buf); - bench_log_long_new(new_buf, calc_log_long_size()); - check("log_long"); - - return all_pass; -} - -// ============================================================================ -// Main -// ============================================================================ - -int main() { - printf("=== ProtoWriteBuffer Encoding Benchmark ===\n"); - printf("Comparing push_back() vs pre-sized pointer writes\n\n"); - - // Verify correctness first - printf("--- Correctness Verification ---\n"); - if (!verify_encoding_match()) { - printf("CORRECTNESS CHECK FAILED - encoding output differs!\n"); - return 1; - } - printf("All encoding outputs match between old and new implementations.\n\n"); - - // Calculate sizes for pre-allocation - size_t varint_size = 1 + 2 + 3 + 4 + 5; // 15 bytes - size_t strings_size = calc_strings_size(); - size_t fixed32_size = calc_fixed32_size(); - size_t sensor_state_size = calc_sensor_state_size(); - size_t list_entities_size = calc_list_entities_size(); - size_t ble_batch_size = calc_ble_batch_size(); - size_t log_msg_size = calc_log_msg_size(); - size_t log_long_size = calc_log_long_size(); - - std::vector buf; - buf.reserve(1024); // Pre-allocate to avoid measuring allocation - - std::vector results; - - // --- Varint encoding --- - printf("--- Running Benchmarks ---\n\n"); - - results.push_back(benchmark("varint_mix (old/push_back)", varint_size, [&] { bench_varint_old(buf); })); - results.push_back(benchmark("varint_mix (new/pointer)", varint_size, [&] { bench_varint_new(buf, varint_size); })); - - // --- String encoding --- - results.push_back(benchmark("strings_mix (old/push_back)", strings_size, [&] { bench_strings_old(buf); })); - results.push_back( - benchmark("strings_mix (new/pointer)", strings_size, [&] { bench_strings_new(buf, strings_size); })); - - // --- Fixed32 encoding --- - results.push_back(benchmark("fixed32_x10 (old/push_back)", fixed32_size, [&] { bench_fixed32_old(buf); })); - results.push_back( - benchmark("fixed32_x10 (new/pointer)", fixed32_size, [&] { bench_fixed32_new(buf, fixed32_size); })); - - // --- SensorStateResponse --- - results.push_back(benchmark("sensor_state (old/push_back)", sensor_state_size, [&] { bench_sensor_state_old(buf); })); - results.push_back(benchmark("sensor_state (new/pointer)", sensor_state_size, - [&] { bench_sensor_state_new(buf, sensor_state_size); })); - - // --- ListEntitiesSensorResponse --- - results.push_back( - benchmark("list_entities (old/push_back)", list_entities_size, [&] { bench_list_entities_old(buf); })); - results.push_back(benchmark("list_entities (new/pointer)", list_entities_size, - [&] { bench_list_entities_new(buf, list_entities_size); })); - - // --- BLE batch --- - results.push_back(benchmark("ble_batch_x8 (old/push_back)", ble_batch_size, [&] { bench_ble_batch_old(buf); })); - results.push_back( - benchmark("ble_batch_x8 (new/pointer)", ble_batch_size, [&] { bench_ble_batch_new(buf, ble_batch_size); })); - - // --- Log messages --- - results.push_back(benchmark("log_short (old/push_back)", log_msg_size, [&] { bench_log_msg_old(buf); })); - results.push_back(benchmark("log_short (new/pointer)", log_msg_size, [&] { bench_log_msg_new(buf, log_msg_size); })); - - results.push_back(benchmark("log_long (old/push_back)", log_long_size, [&] { bench_log_long_old(buf); })); - results.push_back( - benchmark("log_long (new/pointer)", log_long_size, [&] { bench_log_long_new(buf, log_long_size); })); - - // --- Full encode cycle (calculate_size + resize + encode) --- - results.push_back( - benchmark("full_cycle_sensor (old/push_back)", sensor_state_size, [&] { bench_full_cycle_sensor_old(buf); })); - results.push_back( - benchmark("full_cycle_sensor (new/pointer)", sensor_state_size, [&] { bench_full_cycle_sensor_new(buf); })); - - // Print all results - printf("\n--- Results ---\n\n"); - print_results(results); - - // Print comparison summary - printf("\n--- Speedup Summary (new vs old) ---\n\n"); - for (size_t i = 0; i + 1 < results.size(); i += 2) { - print_comparison(results[i].name, results[i], results[i + 1]); - } - - printf("\n--- Encoded Sizes ---\n\n"); - printf(" varint_mix: %3zu bytes\n", varint_size); - printf(" strings_mix: %3zu bytes\n", strings_size); - printf(" fixed32_x10: %3zu bytes\n", fixed32_size); - printf(" sensor_state: %3zu bytes\n", sensor_state_size); - printf(" list_entities: %3zu bytes\n", list_entities_size); - printf(" ble_batch_x8: %3zu bytes\n", ble_batch_size); - printf(" log_short: %3zu bytes\n", log_msg_size); - printf(" log_long: %3zu bytes\n", log_long_size); - - return 0; -} diff --git a/tests/benchmarks/proto_message_benchmark.cpp b/tests/benchmarks/proto_message_benchmark.cpp deleted file mode 100644 index 395cc4b8060..00000000000 --- a/tests/benchmarks/proto_message_benchmark.cpp +++ /dev/null @@ -1,783 +0,0 @@ -/** - * Benchmark: Virtual dispatch vs direct calls for protobuf message encoding - * - * Compares: - * OLD: virtual dispatch for encode/calculate_size + ProtoSize accumulator object - * NEW: direct template calls for encode/calculate_size + static ProtoSize methods - * - * Build (from repo root): - * g++ -std=gnu++20 -O2 \ - * tests/benchmarks/proto_message_benchmark.cpp \ - * -o tests/benchmarks/proto_message_benchmark - * - * Run: - * ./tests/benchmarks/proto_message_benchmark - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -// ============================================================================ -// Benchmark infrastructure -// ============================================================================ - -struct BenchResult { - const char *name; - double ns_per_op; - double ops_per_sec; - size_t iterations; -}; - -template __attribute__((noinline)) void do_not_optimize(T &value) { - asm volatile("" : "+r,m"(value) : : "memory"); -} - -__attribute__((noinline)) void clobber_memory() { asm volatile("" : : : "memory"); } - -template BenchResult benchmark(const char *name, Func func) { - // Warmup - for (int i = 0; i < 1000; i++) { - func(); - } - - // Determine iteration count (target ~100ms) - size_t iterations = 1000; - auto start = std::chrono::high_resolution_clock::now(); - for (size_t i = 0; i < iterations; i++) { - func(); - } - auto end = std::chrono::high_resolution_clock::now(); - double elapsed_ns = std::chrono::duration_cast(end - start).count(); - double ns_per_op = elapsed_ns / iterations; - - // Scale iterations to target ~500ms for stability - iterations = std::max(100000, static_cast(500'000'000.0 / ns_per_op)); - - // Actual benchmark run - start = std::chrono::high_resolution_clock::now(); - for (size_t i = 0; i < iterations; i++) { - func(); - clobber_memory(); - } - end = std::chrono::high_resolution_clock::now(); - elapsed_ns = std::chrono::duration_cast(end - start).count(); - ns_per_op = elapsed_ns / iterations; - - return BenchResult{name, ns_per_op, 1'000'000'000.0 / ns_per_op, iterations}; -} - -void print_results(const std::vector &results) { - printf("%-55s %12s %15s %12s\n", "Benchmark", "ns/op", "ops/sec", "iters"); - printf("%-55s %12s %15s %12s\n", std::string(55, '-').c_str(), "--------", "--------", "--------"); - for (const auto &r : results) { - printf("%-55s %12.1f %15.0f %12zu\n", r.name, r.ns_per_op, r.ops_per_sec, r.iterations); - } -} - -void print_comparison(const char *label, const BenchResult &old_result, const BenchResult &new_result) { - double speedup = old_result.ns_per_op / new_result.ns_per_op; - const char *dir = speedup > 1.0 ? "faster" : "slower"; - printf(" %-51s %5.2fx %s\n", label, speedup > 1.0 ? speedup : 1.0 / speedup, dir); -} - -// ============================================================================ -// Shared encoding helpers (same for both old and new) -// ============================================================================ - -static constexpr uint32_t varint_size(uint32_t value) { - if (value < 128) - return 1; - if (value < 16384) - return 2; - if (value < 2097152) - return 3; - if (value < 268435456) - return 4; - return 5; -} - -class WriteBuffer { - public: - WriteBuffer(std::vector *buffer, size_t write_pos) : buffer_(buffer), pos_(buffer->data() + write_pos) {} - - void encode_varint_raw(uint32_t value) { - while (value > 0x7F) { - *this->pos_++ = static_cast(value | 0x80); - value >>= 7; - } - *this->pos_++ = static_cast(value); - } - - void encode_field_raw(uint32_t field_id, uint32_t type) { this->encode_varint_raw((field_id << 3) | type); } - - void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) { - if (len == 0 && !force) - return; - this->encode_field_raw(field_id, 2); - this->encode_varint_raw(len); - std::memcpy(this->pos_, string, len); - this->pos_ += len; - } - - void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 0); - this->encode_varint_raw(value); - } - - void encode_bool(uint32_t field_id, bool value, bool force = false) { - if (!value && !force) - return; - this->encode_field_raw(field_id, 0); - *this->pos_++ = value ? 0x01 : 0x00; - } - - void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) { - if (value == 0 && !force) - return; - this->encode_field_raw(field_id, 5); - std::memcpy(this->pos_, &value, 4); - this->pos_ += 4; - } - - void encode_float(uint32_t field_id, float value, bool force = false) { - if (value == 0.0f && !force) - return; - union { - float value; - uint32_t raw; - } val{}; - val.value = value; - this->encode_fixed32(field_id, val.raw); - } - - void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { - this->encode_string(field_id, reinterpret_cast(data), len, force); - } - - // Nested message encoding (for old-style virtual dispatch) - void encode_message_virtual(uint32_t field_id, uint32_t nested_size, const void *value, - void (*encode_fn)(const void *, WriteBuffer &), bool force) { - if (nested_size == 0 && !force) - return; - this->encode_field_raw(field_id, 2); - this->encode_varint_raw(nested_size); - encode_fn(value, *this); - } - - // Nested message encoding (for new-style direct calls) - template void encode_message(uint32_t field_id, const T &value, bool force = true) { - uint32_t nested_size = value.calculate_size(); - if (nested_size == 0 && !force) - return; - this->encode_field_raw(field_id, 2); - this->encode_varint_raw(nested_size); - value.encode(*this); - } - - std::vector *buffer_; - uint8_t *pos_; -}; - -// ============================================================================ -// OLD approach: ProtoSize accumulator + virtual dispatch -// ============================================================================ - -namespace old_style { - -class ProtoSize { - public: - ProtoSize() = default; - uint32_t get_size() const { return total_size_; } - - void add_uint32(uint32_t field_id_size, uint32_t value) { - if (value != 0) - total_size_ += field_id_size + varint_size(value); - } - void add_bool(uint32_t field_id_size, bool value) { - if (value) - total_size_ += field_id_size + 1; - } - void add_float(uint32_t field_id_size, float value) { - if (value != 0.0f) - total_size_ += field_id_size + 4; - } - void add_fixed32(uint32_t field_id_size, uint32_t value) { - if (value != 0) - total_size_ += field_id_size + 4; - } - void add_length(uint32_t field_id_size, size_t len) { - if (len != 0) - total_size_ += field_id_size + varint_size(static_cast(len)) + static_cast(len); - } - void add_message_field_force(uint32_t field_id_size, uint32_t nested_size) { - total_size_ += field_id_size + varint_size(nested_size) + nested_size; - } - - private: - uint32_t total_size_ = 0; -}; - -class ProtoMessage { - public: - virtual void encode(WriteBuffer &buffer) const = 0; - virtual uint32_t calculate_size() const = 0; - virtual ~ProtoMessage() = default; -}; - -// Empty message (ping, disconnect, etc.) -class EmptyMessage : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 1; - void encode(WriteBuffer &buffer) const override {} - uint32_t calculate_size() const override { return 0; } -}; - -// SensorStateResponse: fixed32 key, float state, bool missing_state -class SensorStateResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 25; - uint32_t key{0x12345678}; - float state{23.5f}; - bool missing_state{false}; - - void encode(WriteBuffer &buffer) const override { - buffer.encode_fixed32(1, this->key); - buffer.encode_float(2, this->state); - buffer.encode_bool(3, this->missing_state); - } - - uint32_t calculate_size() const override { - ProtoSize size; - size.add_fixed32(1, this->key); - size.add_float(1, this->state); - size.add_bool(1, this->missing_state); - return size.get_size(); - } -}; - -// ListEntitiesSensorResponse: multiple strings + numeric fields -class ListEntitiesSensorResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 16; - std::string object_id{"living_room_temp"}; - uint32_t key{0xABCD1234}; - std::string name{"Living Room Temperature"}; - std::string unique_id{"esp32_01-sensor-living_room_temp"}; - std::string icon{"mdi:thermometer"}; - std::string unit_of_measurement{"\xc2\xb0" - "C"}; - uint32_t accuracy_decimals{1}; - bool force_update{false}; - std::string device_class{"temperature"}; - uint32_t state_class{1}; - - void encode(WriteBuffer &buffer) const override { - buffer.encode_string(1, this->object_id.data(), this->object_id.size()); - buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name.data(), this->name.size()); - buffer.encode_string(4, this->unique_id.data(), this->unique_id.size()); - buffer.encode_string(5, this->icon.data(), this->icon.size()); - buffer.encode_string(6, this->unit_of_measurement.data(), this->unit_of_measurement.size()); - buffer.encode_uint32(7, this->accuracy_decimals); - buffer.encode_bool(8, this->force_update); - buffer.encode_string(9, this->device_class.data(), this->device_class.size()); - buffer.encode_uint32(10, this->state_class); - } - - uint32_t calculate_size() const override { - ProtoSize size; - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); - size.add_length(1, this->unique_id.size()); - size.add_length(1, this->icon.size()); - size.add_length(1, this->unit_of_measurement.size()); - size.add_uint32(1, this->accuracy_decimals); - size.add_bool(1, this->force_update); - size.add_length(1, this->device_class.size()); - size.add_uint32(1, this->state_class); - return size.get_size(); - } -}; - -// SubscribeLogsResponse: level + message bytes -class SubscribeLogsResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 29; - uint32_t level{3}; - std::string message{"[sensor:042]: 'Temperature': Sending state 23.50 C with 1 decimals of accuracy"}; - - void encode(WriteBuffer &buffer) const override { - buffer.encode_uint32(1, this->level); - buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); - } - - uint32_t calculate_size() const override { - ProtoSize size; - size.add_uint32(1, this->level); - size.add_length(1, this->message.size()); - return size.get_size(); - } -}; - -// Nested message: BluetoothGATTService with characteristics -class BluetoothGATTCharacteristic : public ProtoMessage { - public: - uint32_t uuid1{0x2A19}; - uint32_t handle{3}; - uint32_t properties{2}; - - void encode(WriteBuffer &buffer) const override { - buffer.encode_uint32(1, this->uuid1); - buffer.encode_uint32(2, this->handle); - buffer.encode_uint32(3, this->properties); - } - - uint32_t calculate_size() const override { - ProtoSize size; - size.add_uint32(1, this->uuid1); - size.add_uint32(1, this->handle); - size.add_uint32(1, this->properties); - return size.get_size(); - } -}; - -class BluetoothGATTService : public ProtoMessage { - public: - uint32_t uuid1{0x180F}; - uint32_t handle{1}; - std::vector characteristics; - - BluetoothGATTService() { characteristics.resize(4); } - - void encode(WriteBuffer &buffer) const override { - buffer.encode_uint32(1, this->uuid1); - buffer.encode_uint32(2, this->handle); - for (const auto &ch : this->characteristics) { - buffer.encode_message_virtual( - 3, ch.calculate_size(), &ch, - [](const void *msg, WriteBuffer &buf) { static_cast(msg)->encode(buf); }, - true); - } - } - - uint32_t calculate_size() const override { - ProtoSize size; - size.add_uint32(1, this->uuid1); - size.add_uint32(1, this->handle); - for (const auto &ch : this->characteristics) { - size.add_message_field_force(1, ch.calculate_size()); - } - return size.get_size(); - } -}; - -// send_message simulation: virtual dispatch through base pointer -__attribute__((noinline)) bool send_message(const ProtoMessage &msg, uint8_t msg_type, std::vector &buf) { - uint32_t size = msg.calculate_size(); - buf.resize(size); - WriteBuffer writer(&buf, 0); - msg.encode(writer); - do_not_optimize(buf); - return true; -} - -} // namespace old_style - -// ============================================================================ -// NEW approach: static ProtoSize + direct template calls -// ============================================================================ - -namespace new_style { - -class ProtoSize { - public: - static constexpr uint32_t calc_uint32(uint32_t field_id_size, uint32_t value) { - return value ? field_id_size + varint_size(value) : 0; - } - static constexpr uint32_t calc_bool(uint32_t field_id_size, bool value) { return value ? field_id_size + 1 : 0; } - static constexpr uint32_t calc_float(uint32_t field_id_size, float value) { - return value != 0.0f ? field_id_size + 4 : 0; - } - static constexpr uint32_t calc_fixed32(uint32_t field_id_size, uint32_t value) { - return value ? field_id_size + 4 : 0; - } - static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) { - return len ? field_id_size + varint_size(static_cast(len)) + static_cast(len) : 0; - } - static constexpr uint32_t calc_message_force(uint32_t field_id_size, uint32_t nested_size) { - return field_id_size + varint_size(nested_size) + nested_size; - } -}; - -class ProtoMessage { - public: - // Non-virtual defaults — concrete types hide these - void encode(WriteBuffer &buffer) const {} - uint32_t calculate_size() const { return 0; } - ~ProtoMessage() = default; -}; - -// Empty message -class EmptyMessage : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 1; - static constexpr uint32_t ESTIMATED_SIZE = 0; - void encode(WriteBuffer &buffer) const {} - uint32_t calculate_size() const { return 0; } -}; - -// SensorStateResponse -class SensorStateResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 25; - static constexpr uint32_t ESTIMATED_SIZE = 10; - uint32_t key{0x12345678}; - float state{23.5f}; - bool missing_state{false}; - - void encode(WriteBuffer &buffer) const { - buffer.encode_fixed32(1, this->key); - buffer.encode_float(2, this->state); - buffer.encode_bool(3, this->missing_state); - } - - uint32_t calculate_size() const { - uint32_t size = 0; - size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_float(1, this->state); - size += ProtoSize::calc_bool(1, this->missing_state); - return size; - } -}; - -// ListEntitiesSensorResponse -class ListEntitiesSensorResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 16; - static constexpr uint32_t ESTIMATED_SIZE = 128; - std::string object_id{"living_room_temp"}; - uint32_t key{0xABCD1234}; - std::string name{"Living Room Temperature"}; - std::string unique_id{"esp32_01-sensor-living_room_temp"}; - std::string icon{"mdi:thermometer"}; - std::string unit_of_measurement{"\xc2\xb0" - "C"}; - uint32_t accuracy_decimals{1}; - bool force_update{false}; - std::string device_class{"temperature"}; - uint32_t state_class{1}; - - void encode(WriteBuffer &buffer) const { - buffer.encode_string(1, this->object_id.data(), this->object_id.size()); - buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name.data(), this->name.size()); - buffer.encode_string(4, this->unique_id.data(), this->unique_id.size()); - buffer.encode_string(5, this->icon.data(), this->icon.size()); - buffer.encode_string(6, this->unit_of_measurement.data(), this->unit_of_measurement.size()); - buffer.encode_uint32(7, this->accuracy_decimals); - buffer.encode_bool(8, this->force_update); - buffer.encode_string(9, this->device_class.data(), this->device_class.size()); - buffer.encode_uint32(10, this->state_class); - } - - uint32_t calculate_size() const { - uint32_t size = 0; - size += ProtoSize::calc_length(1, this->object_id.size()); - size += ProtoSize::calc_fixed32(1, this->key); - size += ProtoSize::calc_length(1, this->name.size()); - size += ProtoSize::calc_length(1, this->unique_id.size()); - size += ProtoSize::calc_length(1, this->icon.size()); - size += ProtoSize::calc_length(1, this->unit_of_measurement.size()); - size += ProtoSize::calc_uint32(1, this->accuracy_decimals); - size += ProtoSize::calc_bool(1, this->force_update); - size += ProtoSize::calc_length(1, this->device_class.size()); - size += ProtoSize::calc_uint32(1, this->state_class); - return size; - } -}; - -// SubscribeLogsResponse -class SubscribeLogsResponse : public ProtoMessage { - public: - static constexpr uint8_t MESSAGE_TYPE = 29; - static constexpr uint32_t ESTIMATED_SIZE = 80; - uint32_t level{3}; - std::string message{"[sensor:042]: 'Temperature': Sending state 23.50 C with 1 decimals of accuracy"}; - - void encode(WriteBuffer &buffer) const { - buffer.encode_uint32(1, this->level); - buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); - } - - uint32_t calculate_size() const { - uint32_t size = 0; - size += ProtoSize::calc_uint32(1, this->level); - size += ProtoSize::calc_length(1, this->message.size()); - return size; - } -}; - -// Nested: BluetoothGATTCharacteristic -class BluetoothGATTCharacteristic : public ProtoMessage { - public: - static constexpr uint32_t ESTIMATED_SIZE = 10; - uint32_t uuid1{0x2A19}; - uint32_t handle{3}; - uint32_t properties{2}; - - void encode(WriteBuffer &buffer) const { - buffer.encode_uint32(1, this->uuid1); - buffer.encode_uint32(2, this->handle); - buffer.encode_uint32(3, this->properties); - } - - uint32_t calculate_size() const { - uint32_t size = 0; - size += ProtoSize::calc_uint32(1, this->uuid1); - size += ProtoSize::calc_uint32(1, this->handle); - size += ProtoSize::calc_uint32(1, this->properties); - return size; - } -}; - -// Nested: BluetoothGATTService -class BluetoothGATTService : public ProtoMessage { - public: - static constexpr uint32_t ESTIMATED_SIZE = 64; - uint32_t uuid1{0x180F}; - uint32_t handle{1}; - std::vector characteristics; - - BluetoothGATTService() { characteristics.resize(4); } - - void encode(WriteBuffer &buffer) const { - buffer.encode_uint32(1, this->uuid1); - buffer.encode_uint32(2, this->handle); - for (const auto &ch : this->characteristics) { - buffer.encode_message(3, ch, true); - } - } - - uint32_t calculate_size() const { - uint32_t size = 0; - size += ProtoSize::calc_uint32(1, this->uuid1); - size += ProtoSize::calc_uint32(1, this->handle); - for (const auto &ch : this->characteristics) { - size += ProtoSize::calc_message_force(1, ch.calculate_size()); - } - return size; - } -}; - -// Encode thunk for non-template core -template void encode_msg(const void *msg, WriteBuffer &buf) { static_cast(msg)->encode(buf); } - -static void encode_msg_noop(const void *, WriteBuffer &) {} - -// send_message template: direct calls, no virtual dispatch -template __attribute__((noinline)) bool send_message(const T &msg, std::vector &buf) { - uint32_t size; - void (*encode_fn)(const void *, WriteBuffer &); - if constexpr (T::ESTIMATED_SIZE == 0) { - size = 0; - encode_fn = &encode_msg_noop; - } else { - size = msg.calculate_size(); - encode_fn = &encode_msg; - } - buf.resize(size); - WriteBuffer writer(&buf, 0); - encode_fn(&msg, writer); - do_not_optimize(buf); - return true; -} - -} // namespace new_style - -// ============================================================================ -// Correctness verification -// ============================================================================ - -static bool verify_correctness() { - std::vector old_buf, new_buf; - bool all_pass = true; - - auto check = [&](const char *name) { - if (old_buf.size() != new_buf.size() || - (old_buf.size() > 0 && memcmp(old_buf.data(), new_buf.data(), old_buf.size()) != 0)) { - printf("FAIL: %s - output mismatch (old=%zu bytes, new=%zu bytes)\n", name, old_buf.size(), new_buf.size()); - all_pass = false; - } else { - printf(" OK: %s (%zu bytes)\n", name, old_buf.size()); - } - }; - - // Empty - { - old_style::EmptyMessage old_msg; - new_style::EmptyMessage new_msg; - old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); - new_style::send_message(new_msg, new_buf); - check("EmptyMessage"); - } - // SensorState - { - old_style::SensorStateResponse old_msg; - new_style::SensorStateResponse new_msg; - old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); - new_style::send_message(new_msg, new_buf); - check("SensorStateResponse"); - } - // ListEntities - { - old_style::ListEntitiesSensorResponse old_msg; - new_style::ListEntitiesSensorResponse new_msg; - old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); - new_style::send_message(new_msg, new_buf); - check("ListEntitiesSensorResponse"); - } - // Log - { - old_style::SubscribeLogsResponse old_msg; - new_style::SubscribeLogsResponse new_msg; - old_style::send_message(old_msg, old_msg.MESSAGE_TYPE, old_buf); - new_style::send_message(new_msg, new_buf); - check("SubscribeLogsResponse"); - } - // Nested (GATT service) - { - old_style::BluetoothGATTService old_msg; - new_style::BluetoothGATTService new_msg; - old_style::send_message(old_msg, 7, old_buf); - new_style::send_message(new_msg, new_buf); - check("BluetoothGATTService (nested)"); - } - - return all_pass; -} - -// ============================================================================ -// Benchmark: calculate_size only -// ============================================================================ - -template __attribute__((noinline)) uint32_t bench_calc_size_virtual(const T &msg) { - // Force virtual dispatch by going through base pointer - const old_style::ProtoMessage *base = &msg; - uint32_t s = base->calculate_size(); - do_not_optimize(s); - return s; -} - -template __attribute__((noinline)) uint32_t bench_calc_size_direct(const T &msg) { - uint32_t s = msg.calculate_size(); - do_not_optimize(s); - return s; -} - -// ============================================================================ -// Main -// ============================================================================ - -int main() { - printf("=== Proto Message Encoding Benchmark ===\n"); - printf("Comparing virtual dispatch + accumulator ProtoSize vs direct calls + static ProtoSize\n\n"); - - // Verify correctness - printf("--- Correctness Verification ---\n"); - if (!verify_correctness()) { - printf("\nCORRECTNESS CHECK FAILED!\n"); - return 1; - } - printf("All outputs match.\n\n"); - - std::vector buf; - buf.reserve(1024); - - std::vector results; - - // ---- calculate_size benchmarks ---- - printf("--- Running calculate_size Benchmarks ---\n\n"); - - { - old_style::SensorStateResponse old_msg; - new_style::SensorStateResponse new_msg; - results.push_back(benchmark("calc_size: SensorState (virtual)", [&] { bench_calc_size_virtual(old_msg); })); - results.push_back(benchmark("calc_size: SensorState (direct+static)", [&] { bench_calc_size_direct(new_msg); })); - } - { - old_style::ListEntitiesSensorResponse old_msg; - new_style::ListEntitiesSensorResponse new_msg; - results.push_back(benchmark("calc_size: ListEntities (virtual)", [&] { bench_calc_size_virtual(old_msg); })); - results.push_back(benchmark("calc_size: ListEntities (direct+static)", [&] { bench_calc_size_direct(new_msg); })); - } - { - old_style::SubscribeLogsResponse old_msg; - new_style::SubscribeLogsResponse new_msg; - results.push_back(benchmark("calc_size: LogResponse (virtual)", [&] { bench_calc_size_virtual(old_msg); })); - results.push_back(benchmark("calc_size: LogResponse (direct+static)", [&] { bench_calc_size_direct(new_msg); })); - } - { - old_style::BluetoothGATTService old_msg; - new_style::BluetoothGATTService new_msg; - results.push_back(benchmark("calc_size: GATTService/nested (virtual)", [&] { bench_calc_size_virtual(old_msg); })); - results.push_back( - benchmark("calc_size: GATTService/nested (direct+static)", [&] { bench_calc_size_direct(new_msg); })); - } - - // ---- Full send_message benchmarks ---- - printf("--- Running send_message Benchmarks ---\n\n"); - - { - old_style::EmptyMessage old_msg; - new_style::EmptyMessage new_msg; - results.push_back(benchmark("send: EmptyMessage (virtual)", [&] { old_style::send_message(old_msg, 1, buf); })); - results.push_back(benchmark("send: EmptyMessage (direct+static)", [&] { new_style::send_message(new_msg, buf); })); - } - { - old_style::SensorStateResponse old_msg; - new_style::SensorStateResponse new_msg; - results.push_back(benchmark("send: SensorState (virtual)", [&] { old_style::send_message(old_msg, 25, buf); })); - results.push_back(benchmark("send: SensorState (direct+static)", [&] { new_style::send_message(new_msg, buf); })); - } - { - old_style::ListEntitiesSensorResponse old_msg; - new_style::ListEntitiesSensorResponse new_msg; - results.push_back(benchmark("send: ListEntities (virtual)", [&] { old_style::send_message(old_msg, 16, buf); })); - results.push_back(benchmark("send: ListEntities (direct+static)", [&] { new_style::send_message(new_msg, buf); })); - } - { - old_style::SubscribeLogsResponse old_msg; - new_style::SubscribeLogsResponse new_msg; - results.push_back(benchmark("send: LogResponse (virtual)", [&] { old_style::send_message(old_msg, 29, buf); })); - results.push_back(benchmark("send: LogResponse (direct+static)", [&] { new_style::send_message(new_msg, buf); })); - } - { - old_style::BluetoothGATTService old_msg; - new_style::BluetoothGATTService new_msg; - results.push_back( - benchmark("send: GATTService/nested (virtual)", [&] { old_style::send_message(old_msg, 7, buf); })); - results.push_back( - benchmark("send: GATTService/nested (direct+static)", [&] { new_style::send_message(new_msg, buf); })); - } - - // Print all results - printf("\n--- Results ---\n\n"); - print_results(results); - - // Print comparison summary - printf("\n--- Speedup Summary (new vs old) ---\n\n"); - for (size_t i = 0; i + 1 < results.size(); i += 2) { - print_comparison(results[i].name, results[i], results[i + 1]); - } - - return 0; -} From 765075b1d0534f84934e73cee97dd33fc8448b27 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 21:35:11 -1000 Subject: [PATCH 24/42] tweaks --- esphome/components/api/proto.h | 3 ++- script/api_protobuf/api_protobuf.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index cf03f48be84..702208d9de6 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -468,7 +468,8 @@ class ProtoMessage { virtual const char *message_name() const { return "unknown"; } #endif - // Non-virtual: messages are never deleted polymorphically. + protected: + // Non-virtual destructor is protected to prevent polymorphic deletion. ~ProtoMessage() = default; }; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index b00cbab37a3..85352689e6b 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -280,6 +280,9 @@ class TypeInfo(ABC): """ field_id_size = self.calculate_field_id_size() method = f"calc_{base_method}_force" if force else f"calc_{base_method}" + # calc_bool_force only takes field_id_size (no value needed - bool is always 1 byte) + if base_method == "bool" and force: + return f"size += ProtoSize::{method}({field_id_size});" value = value_expr or name return f"size += ProtoSize::{method}({field_id_size}, {value});" From 36a598fa40e16f49ec6eba5cc5ebef6e23f39b7b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 22:22:51 -1000 Subject: [PATCH 25/42] [core] Call loop() directly in main loop, bypass call() indirection In the main loop, components in looping_components_ active section are guaranteed to be in LOOP state. The call() method's state machine dispatch (checking CONSTRUCTION, SETUP, FAILED, LOOP_DONE) is only needed during Application::setup(). In the main loop it adds two unnecessary function call frames per component per iteration (call() -> call_loop_() -> loop()). This became dead weight when looping_components_ partitioning was introduced in June 2025 (8a06c4380d). Before that, Application::loop() iterated components_[] which contained all states, so the state check was necessary. --- esphome/core/application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 8c2ba58c86e..f827783503f 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -173,7 +173,7 @@ void Application::loop() { { this->set_current_component(component); WarnIfComponentBlockingGuard guard{component, last_op_end_time}; - component->call(); + component->loop(); // Use the finish method to get the current time as the end time last_op_end_time = guard.finish(); } From fe0436166c12eff9672f58d38a9fed64d30504e8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 22:31:04 -1000 Subject: [PATCH 26/42] =?UTF-8?q?[core]=20Ensure=20SETUP=E2=86=92LOOP=20tr?= =?UTF-8?q?ansition=20before=20main=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Components after the last blocking component in setup only receive one call() (CONSTRUCTION→SETUP) and never get the second call() that would transition them to LOOP state. Explicitly transition all active looping components to LOOP state at the end of setup() so the main loop can call loop() directly without the call() state machine wrapper. --- esphome/core/application.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index f827783503f..db1c8a0c0a1 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -153,6 +153,14 @@ void Application::setup() { this->setup_wake_loop_threadsafe_(); #endif + // Ensure all active looping components are in LOOP state. + // Components after the last blocking component only got one call() during setup + // (CONSTRUCTION→SETUP) and never received the second call() (SETUP→LOOP). + // The main loop calls loop() directly, bypassing call()'s state machine. + for (uint16_t i = 0; i < this->looping_components_active_end_; i++) { + this->looping_components_[i]->set_component_state_(COMPONENT_STATE_LOOP); + } + this->schedule_dump_config(); } void Application::loop() { From 87f37b7c380e40ff1c08e56a40548555b92bbc3c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Mar 2026 23:06:28 -1000 Subject: [PATCH 27/42] [runtime_stats] Use micros() for accurate per-component timing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous millis()-based timing had insufficient resolution. Most components complete their loop() in microseconds, but millis() only has 1ms granularity. Components taking <1ms would show either 0ms or 1ms depending on whether a millisecond boundary happened to tick over during execution — essentially random noise rather than useful data. Switch to self-timed micros() per guard (only when USE_RUNTIME_STATS is compiled in — zero cost in production builds). Track internally in microseconds, display in milliseconds with fractional precision. Use uint64_t for total_time_us_ to avoid overflow (uint32_t would wrap after ~10 hours at typical loop rates). --- .../runtime_stats/runtime_stats.cpp | 22 ++++---- .../components/runtime_stats/runtime_stats.h | 56 +++++++++---------- esphome/core/component.cpp | 7 ++- esphome/core/component.h | 16 +++++- 4 files changed, 60 insertions(+), 41 deletions(-) diff --git a/esphome/components/runtime_stats/runtime_stats.cpp b/esphome/components/runtime_stats/runtime_stats.cpp index 410695da040..d9fa22d9495 100644 --- a/esphome/components/runtime_stats/runtime_stats.cpp +++ b/esphome/components/runtime_stats/runtime_stats.cpp @@ -13,12 +13,12 @@ RuntimeStatsCollector::RuntimeStatsCollector() : log_interval_(60000), next_log_ global_runtime_stats = this; } -void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time) { +void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_us, uint32_t current_time) { if (component == nullptr) return; // Record stats using component pointer as key - this->component_stats_[component].record_time(duration_ms); + this->component_stats_[component].record_time(duration_us); if (this->next_log_time_ == 0) { this->next_log_time_ = current_time + this->log_interval_; @@ -58,15 +58,16 @@ void RuntimeStatsCollector::log_stats_() { // Sort by period runtime (descending) std::sort(sorted, sorted + count, [this](Component *a, Component *b) { - return this->component_stats_[a].get_period_time_ms() > this->component_stats_[b].get_period_time_ms(); + return this->component_stats_[a].get_period_time_us() > this->component_stats_[b].get_period_time_us(); }); // Log top components by period runtime for (size_t i = 0; i < count; i++) { const auto &stats = this->component_stats_[sorted[i]]; - ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", - LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_period_count(), stats.get_period_avg_time_ms(), - stats.get_period_max_time_ms(), stats.get_period_time_ms()); + ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.3fms, max=%.2fms, total=%.1fms", + LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_period_count(), + stats.get_period_avg_time_us() / 1000.0f, stats.get_period_max_time_us() / 1000.0f, + stats.get_period_time_us() / 1000.0f); } // Log total stats since boot (only for active components - idle ones haven't changed) @@ -74,14 +75,15 @@ void RuntimeStatsCollector::log_stats_() { // Re-sort by total runtime for all-time stats std::sort(sorted, sorted + count, [this](Component *a, Component *b) { - return this->component_stats_[a].get_total_time_ms() > this->component_stats_[b].get_total_time_ms(); + return this->component_stats_[a].get_total_time_us() > this->component_stats_[b].get_total_time_us(); }); for (size_t i = 0; i < count; i++) { const auto &stats = this->component_stats_[sorted[i]]; - ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", - LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_total_count(), stats.get_total_avg_time_ms(), - stats.get_total_max_time_ms(), stats.get_total_time_ms()); + ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.3fms, max=%.2fms, total=%.1fms", + LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_total_count(), + stats.get_total_avg_time_us() / 1000.0f, stats.get_total_max_time_us() / 1000.0f, + stats.get_total_time_us() / 1000.0); } } diff --git a/esphome/components/runtime_stats/runtime_stats.h b/esphome/components/runtime_stats/runtime_stats.h index c7fea7474b5..08475297208 100644 --- a/esphome/components/runtime_stats/runtime_stats.h +++ b/esphome/components/runtime_stats/runtime_stats.h @@ -22,58 +22,58 @@ class ComponentRuntimeStats { public: ComponentRuntimeStats() : period_count_(0), - period_time_ms_(0), - period_max_time_ms_(0), + period_time_us_(0), + period_max_time_us_(0), total_count_(0), - total_time_ms_(0), - total_max_time_ms_(0) {} + total_time_us_(0), + total_max_time_us_(0) {} - void record_time(uint32_t duration_ms) { + void record_time(uint32_t duration_us) { // Update period counters this->period_count_++; - this->period_time_ms_ += duration_ms; - if (duration_ms > this->period_max_time_ms_) - this->period_max_time_ms_ = duration_ms; + this->period_time_us_ += duration_us; + if (duration_us > this->period_max_time_us_) + this->period_max_time_us_ = duration_us; - // Update total counters + // Update total counters (uint64_t to avoid overflow — uint32_t would overflow after ~10 hours) this->total_count_++; - this->total_time_ms_ += duration_ms; - if (duration_ms > this->total_max_time_ms_) - this->total_max_time_ms_ = duration_ms; + this->total_time_us_ += duration_us; + if (duration_us > this->total_max_time_us_) + this->total_max_time_us_ = duration_us; } void reset_period_stats() { this->period_count_ = 0; - this->period_time_ms_ = 0; - this->period_max_time_ms_ = 0; + this->period_time_us_ = 0; + this->period_max_time_us_ = 0; } // Period stats (reset each logging interval) uint32_t get_period_count() const { return this->period_count_; } - uint32_t get_period_time_ms() const { return this->period_time_ms_; } - uint32_t get_period_max_time_ms() const { return this->period_max_time_ms_; } - float get_period_avg_time_ms() const { - return this->period_count_ > 0 ? this->period_time_ms_ / static_cast(this->period_count_) : 0.0f; + uint32_t get_period_time_us() const { return this->period_time_us_; } + uint32_t get_period_max_time_us() const { return this->period_max_time_us_; } + float get_period_avg_time_us() const { + return this->period_count_ > 0 ? this->period_time_us_ / static_cast(this->period_count_) : 0.0f; } - // Total stats (persistent until reboot) + // Total stats (persistent until reboot, uint64_t to avoid overflow) uint32_t get_total_count() const { return this->total_count_; } - uint32_t get_total_time_ms() const { return this->total_time_ms_; } - uint32_t get_total_max_time_ms() const { return this->total_max_time_ms_; } - float get_total_avg_time_ms() const { - return this->total_count_ > 0 ? this->total_time_ms_ / static_cast(this->total_count_) : 0.0f; + uint64_t get_total_time_us() const { return this->total_time_us_; } + uint32_t get_total_max_time_us() const { return this->total_max_time_us_; } + float get_total_avg_time_us() const { + return this->total_count_ > 0 ? this->total_time_us_ / static_cast(this->total_count_) : 0.0f; } protected: // Period stats (reset each logging interval) uint32_t period_count_; - uint32_t period_time_ms_; - uint32_t period_max_time_ms_; + uint32_t period_time_us_; + uint32_t period_max_time_us_; // Total stats (persistent until reboot) uint32_t total_count_; - uint32_t total_time_ms_; - uint32_t total_max_time_ms_; + uint64_t total_time_us_; + uint32_t total_max_time_us_; }; class RuntimeStatsCollector { @@ -83,7 +83,7 @@ class RuntimeStatsCollector { void set_log_interval(uint32_t log_interval) { this->log_interval_ = log_interval; } uint32_t get_log_interval() const { return this->log_interval_; } - void record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time); + void record_component_time(Component *component, uint32_t duration_us, uint32_t current_time); // Process any pending stats printing (should be called after component loop) void process_pending_stats(uint32_t current_time); diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 4ccc7478191..8c2c8d38e8a 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -529,9 +529,12 @@ uint32_t WarnIfComponentBlockingGuard::finish() { uint32_t curr_time = millis(); uint32_t blocking_time = curr_time - this->started_; #ifdef USE_RUNTIME_STATS - // Record component runtime stats + // Use micros() for accurate sub-millisecond timing. millis() has insufficient + // resolution — most components complete in microseconds but millis() only has + // 1ms granularity, so results were essentially random noise. if (global_runtime_stats != nullptr) { - global_runtime_stats->record_component_time(this->component_, blocking_time, curr_time); + uint32_t duration_us = micros() - this->started_us_; + global_runtime_stats->record_component_time(this->component_, duration_us, curr_time); } #endif if (blocking_time > WARN_IF_BLOCKING_OVER_MS) { diff --git a/esphome/core/component.h b/esphome/core/component.h index e5127b0c9f2..59222dc4f47 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -563,10 +563,21 @@ class PollingComponent : public Component { uint32_t update_interval_; }; +#ifdef USE_RUNTIME_STATS +uint32_t micros(); // Forward declare for inline constructor +#endif + class WarnIfComponentBlockingGuard { public: WarnIfComponentBlockingGuard(Component *component, uint32_t start_time) - : started_(start_time), component_(component) {} + : started_(start_time), + component_(component) +#ifdef USE_RUNTIME_STATS + , + started_us_(micros()) +#endif + { + } // Finish the timing operation and return the current time uint32_t finish(); @@ -576,6 +587,9 @@ class WarnIfComponentBlockingGuard { protected: uint32_t started_; Component *component_; +#ifdef USE_RUNTIME_STATS + uint32_t started_us_; +#endif }; // Function to clear setup priority overrides after all components are set up From 37146ff565aa239338948401b8493210af6ba5da Mon Sep 17 00:00:00 2001 From: JiriPrchal <163323169+JiriPrchal@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:00:09 +0100 Subject: [PATCH 28/42] [integration] Add set method to publish and save sensor value (#13316) Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> --- .../integration/integration_sensor.h | 13 ++++++---- esphome/components/integration/sensor.py | 25 +++++++++++++++++-- .../components/integration/common-esp32.yaml | 10 ++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/esphome/components/integration/integration_sensor.h b/esphome/components/integration/integration_sensor.h index f075d163fec..6c4ef7049bb 100644 --- a/esphome/components/integration/integration_sensor.h +++ b/esphome/components/integration/integration_sensor.h @@ -32,6 +32,7 @@ class IntegrationSensor : public sensor::Sensor, public Component { void set_method(IntegrationMethod method) { method_ = method; } void set_restore(bool restore) { restore_ = restore; } void reset() { this->publish_and_save_(0.0f); } + void set_value(float value) { this->publish_and_save_(value); } protected: void process_sensor_value_(float value); @@ -71,14 +72,16 @@ class IntegrationSensor : public sensor::Sensor, public Component { float last_value_{0.0f}; }; -template class ResetAction : public Action { +template class ResetAction : public Action, public Parented { public: - explicit ResetAction(IntegrationSensor *parent) : parent_(parent) {} - void play(const Ts &...x) override { this->parent_->reset(); } +}; - protected: - IntegrationSensor *parent_; +template class SetValueAction : public Action, public Parented { + public: + TEMPLATABLE_VALUE(float, value) + + void play(const Ts &...x) override { this->parent_->set_value(this->value_.value(x...)); } }; } // namespace integration diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py index 3c04a338dde..26766385565 100644 --- a/esphome/components/integration/sensor.py +++ b/esphome/components/integration/sensor.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_RESTORE, CONF_SENSOR, CONF_UNIT_OF_MEASUREMENT, + CONF_VALUE, ) from esphome.core.entity_helpers import inherit_property_from @@ -17,6 +18,7 @@ IntegrationSensor = integration_ns.class_( "IntegrationSensor", sensor.Sensor, cg.Component ) ResetAction = integration_ns.class_("ResetAction", automation.Action) +SetValueAction = integration_ns.class_("SetValueAction", automation.Action) IntegrationSensorTime = integration_ns.enum("IntegrationSensorTime") INTEGRATION_TIMES = { @@ -111,5 +113,24 @@ async def to_code(config): ), ) async def sensor_integration_reset_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - return cg.new_Pvariable(action_id, template_arg, paren) + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + return var + + +@automation.register_action( + "sensor.integration.set_value", + SetValueAction, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(IntegrationSensor), + cv.Required(CONF_VALUE): cv.templatable(cv.float_), + } + ), +) +async def sensor_integration_set_value_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + template_ = await cg.templatable(config[CONF_VALUE], args, float) + cg.add(var.set_value(template_)) + return var diff --git a/tests/components/integration/common-esp32.yaml b/tests/components/integration/common-esp32.yaml index 248106fd608..26550d3c5c9 100644 --- a/tests/components/integration/common-esp32.yaml +++ b/tests/components/integration/common-esp32.yaml @@ -1,9 +1,19 @@ +esphome: + on_boot: + then: + - sensor.integration.reset: + id: integration_sensor + - sensor.integration.set_value: + id: integration_sensor + value: 100.0 + sensor: - platform: adc id: my_sensor pin: ${pin} attenuation: 12db - platform: integration + id: integration_sensor sensor: my_sensor name: Integration Sensor time_unit: s From 065773ed4c3e84243e483409aefba0403c92f9a4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 07:17:28 -1000 Subject: [PATCH 29/42] [runtime_stats] Use micros() for accurate per-component timing (#14452) --- .../runtime_stats/runtime_stats.cpp | 22 ++++---- .../components/runtime_stats/runtime_stats.h | 56 +++++++++---------- esphome/core/component.cpp | 7 ++- esphome/core/component.h | 16 +++++- 4 files changed, 60 insertions(+), 41 deletions(-) diff --git a/esphome/components/runtime_stats/runtime_stats.cpp b/esphome/components/runtime_stats/runtime_stats.cpp index 410695da040..d9fa22d9495 100644 --- a/esphome/components/runtime_stats/runtime_stats.cpp +++ b/esphome/components/runtime_stats/runtime_stats.cpp @@ -13,12 +13,12 @@ RuntimeStatsCollector::RuntimeStatsCollector() : log_interval_(60000), next_log_ global_runtime_stats = this; } -void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time) { +void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_us, uint32_t current_time) { if (component == nullptr) return; // Record stats using component pointer as key - this->component_stats_[component].record_time(duration_ms); + this->component_stats_[component].record_time(duration_us); if (this->next_log_time_ == 0) { this->next_log_time_ = current_time + this->log_interval_; @@ -58,15 +58,16 @@ void RuntimeStatsCollector::log_stats_() { // Sort by period runtime (descending) std::sort(sorted, sorted + count, [this](Component *a, Component *b) { - return this->component_stats_[a].get_period_time_ms() > this->component_stats_[b].get_period_time_ms(); + return this->component_stats_[a].get_period_time_us() > this->component_stats_[b].get_period_time_us(); }); // Log top components by period runtime for (size_t i = 0; i < count; i++) { const auto &stats = this->component_stats_[sorted[i]]; - ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", - LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_period_count(), stats.get_period_avg_time_ms(), - stats.get_period_max_time_ms(), stats.get_period_time_ms()); + ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.3fms, max=%.2fms, total=%.1fms", + LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_period_count(), + stats.get_period_avg_time_us() / 1000.0f, stats.get_period_max_time_us() / 1000.0f, + stats.get_period_time_us() / 1000.0f); } // Log total stats since boot (only for active components - idle ones haven't changed) @@ -74,14 +75,15 @@ void RuntimeStatsCollector::log_stats_() { // Re-sort by total runtime for all-time stats std::sort(sorted, sorted + count, [this](Component *a, Component *b) { - return this->component_stats_[a].get_total_time_ms() > this->component_stats_[b].get_total_time_ms(); + return this->component_stats_[a].get_total_time_us() > this->component_stats_[b].get_total_time_us(); }); for (size_t i = 0; i < count; i++) { const auto &stats = this->component_stats_[sorted[i]]; - ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", - LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_total_count(), stats.get_total_avg_time_ms(), - stats.get_total_max_time_ms(), stats.get_total_time_ms()); + ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.3fms, max=%.2fms, total=%.1fms", + LOG_STR_ARG(sorted[i]->get_component_log_str()), stats.get_total_count(), + stats.get_total_avg_time_us() / 1000.0f, stats.get_total_max_time_us() / 1000.0f, + stats.get_total_time_us() / 1000.0); } } diff --git a/esphome/components/runtime_stats/runtime_stats.h b/esphome/components/runtime_stats/runtime_stats.h index c7fea7474b5..08475297208 100644 --- a/esphome/components/runtime_stats/runtime_stats.h +++ b/esphome/components/runtime_stats/runtime_stats.h @@ -22,58 +22,58 @@ class ComponentRuntimeStats { public: ComponentRuntimeStats() : period_count_(0), - period_time_ms_(0), - period_max_time_ms_(0), + period_time_us_(0), + period_max_time_us_(0), total_count_(0), - total_time_ms_(0), - total_max_time_ms_(0) {} + total_time_us_(0), + total_max_time_us_(0) {} - void record_time(uint32_t duration_ms) { + void record_time(uint32_t duration_us) { // Update period counters this->period_count_++; - this->period_time_ms_ += duration_ms; - if (duration_ms > this->period_max_time_ms_) - this->period_max_time_ms_ = duration_ms; + this->period_time_us_ += duration_us; + if (duration_us > this->period_max_time_us_) + this->period_max_time_us_ = duration_us; - // Update total counters + // Update total counters (uint64_t to avoid overflow — uint32_t would overflow after ~10 hours) this->total_count_++; - this->total_time_ms_ += duration_ms; - if (duration_ms > this->total_max_time_ms_) - this->total_max_time_ms_ = duration_ms; + this->total_time_us_ += duration_us; + if (duration_us > this->total_max_time_us_) + this->total_max_time_us_ = duration_us; } void reset_period_stats() { this->period_count_ = 0; - this->period_time_ms_ = 0; - this->period_max_time_ms_ = 0; + this->period_time_us_ = 0; + this->period_max_time_us_ = 0; } // Period stats (reset each logging interval) uint32_t get_period_count() const { return this->period_count_; } - uint32_t get_period_time_ms() const { return this->period_time_ms_; } - uint32_t get_period_max_time_ms() const { return this->period_max_time_ms_; } - float get_period_avg_time_ms() const { - return this->period_count_ > 0 ? this->period_time_ms_ / static_cast(this->period_count_) : 0.0f; + uint32_t get_period_time_us() const { return this->period_time_us_; } + uint32_t get_period_max_time_us() const { return this->period_max_time_us_; } + float get_period_avg_time_us() const { + return this->period_count_ > 0 ? this->period_time_us_ / static_cast(this->period_count_) : 0.0f; } - // Total stats (persistent until reboot) + // Total stats (persistent until reboot, uint64_t to avoid overflow) uint32_t get_total_count() const { return this->total_count_; } - uint32_t get_total_time_ms() const { return this->total_time_ms_; } - uint32_t get_total_max_time_ms() const { return this->total_max_time_ms_; } - float get_total_avg_time_ms() const { - return this->total_count_ > 0 ? this->total_time_ms_ / static_cast(this->total_count_) : 0.0f; + uint64_t get_total_time_us() const { return this->total_time_us_; } + uint32_t get_total_max_time_us() const { return this->total_max_time_us_; } + float get_total_avg_time_us() const { + return this->total_count_ > 0 ? this->total_time_us_ / static_cast(this->total_count_) : 0.0f; } protected: // Period stats (reset each logging interval) uint32_t period_count_; - uint32_t period_time_ms_; - uint32_t period_max_time_ms_; + uint32_t period_time_us_; + uint32_t period_max_time_us_; // Total stats (persistent until reboot) uint32_t total_count_; - uint32_t total_time_ms_; - uint32_t total_max_time_ms_; + uint64_t total_time_us_; + uint32_t total_max_time_us_; }; class RuntimeStatsCollector { @@ -83,7 +83,7 @@ class RuntimeStatsCollector { void set_log_interval(uint32_t log_interval) { this->log_interval_ = log_interval; } uint32_t get_log_interval() const { return this->log_interval_; } - void record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time); + void record_component_time(Component *component, uint32_t duration_us, uint32_t current_time); // Process any pending stats printing (should be called after component loop) void process_pending_stats(uint32_t current_time); diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 4ccc7478191..8c2c8d38e8a 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -529,9 +529,12 @@ uint32_t WarnIfComponentBlockingGuard::finish() { uint32_t curr_time = millis(); uint32_t blocking_time = curr_time - this->started_; #ifdef USE_RUNTIME_STATS - // Record component runtime stats + // Use micros() for accurate sub-millisecond timing. millis() has insufficient + // resolution — most components complete in microseconds but millis() only has + // 1ms granularity, so results were essentially random noise. if (global_runtime_stats != nullptr) { - global_runtime_stats->record_component_time(this->component_, blocking_time, curr_time); + uint32_t duration_us = micros() - this->started_us_; + global_runtime_stats->record_component_time(this->component_, duration_us, curr_time); } #endif if (blocking_time > WARN_IF_BLOCKING_OVER_MS) { diff --git a/esphome/core/component.h b/esphome/core/component.h index e5127b0c9f2..59222dc4f47 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -563,10 +563,21 @@ class PollingComponent : public Component { uint32_t update_interval_; }; +#ifdef USE_RUNTIME_STATS +uint32_t micros(); // Forward declare for inline constructor +#endif + class WarnIfComponentBlockingGuard { public: WarnIfComponentBlockingGuard(Component *component, uint32_t start_time) - : started_(start_time), component_(component) {} + : started_(start_time), + component_(component) +#ifdef USE_RUNTIME_STATS + , + started_us_(micros()) +#endif + { + } // Finish the timing operation and return the current time uint32_t finish(); @@ -576,6 +587,9 @@ class WarnIfComponentBlockingGuard { protected: uint32_t started_; Component *component_; +#ifdef USE_RUNTIME_STATS + uint32_t started_us_; +#endif }; // Function to clear setup priority overrides after all components are set up From ac19d05db26a891b6dd0d4301b8e8321f9c48fe0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 07:17:41 -1000 Subject: [PATCH 30/42] [core] Call loop() directly in main loop, bypass call() indirection (#14451) --- esphome/core/application.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 8c2ba58c86e..db1c8a0c0a1 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -153,6 +153,14 @@ void Application::setup() { this->setup_wake_loop_threadsafe_(); #endif + // Ensure all active looping components are in LOOP state. + // Components after the last blocking component only got one call() during setup + // (CONSTRUCTION→SETUP) and never received the second call() (SETUP→LOOP). + // The main loop calls loop() directly, bypassing call()'s state machine. + for (uint16_t i = 0; i < this->looping_components_active_end_; i++) { + this->looping_components_[i]->set_component_state_(COMPONENT_STATE_LOOP); + } + this->schedule_dump_config(); } void Application::loop() { @@ -173,7 +181,7 @@ void Application::loop() { { this->set_current_component(component); WarnIfComponentBlockingGuard guard{component, last_op_end_time}; - component->call(); + component->loop(); // Use the finish method to get the current time as the end time last_op_end_time = guard.finish(); } From b2e8544c584c29a923a88622a7b7ba10373a761f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 07:18:31 -1000 Subject: [PATCH 31/42] [ld2412] Add integration tests with mock UART (#14448) --- .../fixtures/uart_mock_ld2412.yaml | 171 ++++++++ .../uart_mock_ld2412_engineering.yaml | 213 +++++++++ tests/integration/test_uart_mock_ld2412.py | 407 ++++++++++++++++++ 3 files changed, 791 insertions(+) create mode 100644 tests/integration/fixtures/uart_mock_ld2412.yaml create mode 100644 tests/integration/fixtures/uart_mock_ld2412_engineering.yaml create mode 100644 tests/integration/test_uart_mock_ld2412.py diff --git a/tests/integration/fixtures/uart_mock_ld2412.yaml b/tests/integration/fixtures/uart_mock_ld2412.yaml new file mode 100644 index 00000000000..a502f36a253 --- /dev/null +++ b/tests/integration/fixtures/uart_mock_ld2412.yaml @@ -0,0 +1,171 @@ +esphome: + name: uart-mock-ld2412-test + +host: +api: +logger: + level: VERBOSE + +external_components: + - source: + type: local + path: EXTERNAL_COMPONENT_PATH + +# Dummy uart entry to satisfy ld2412's DEPENDENCIES = ["uart"] +# The actual UART bus used is the uart_mock component below +uart: + baud_rate: 115200 + port: /dev/null + +uart_mock: + id: mock_uart + baud_rate: 256000 + injections: + # Phase 1 (t=100ms): Valid LD2412 normal mode data frame - happy path + # The buffer is clean at this point, so this frame should parse correctly. + # Moving target: 100cm, energy 50 + # Still target: 120cm, energy 25 + # Target state: 0x03 (moving + still) + # detection_distance = 100 (LD2412 computes from moving target when MOVE_BITMASK set) + # + # Frame layout (24 bytes): + # [0-3] F4 F3 F2 F1 = data frame header + # [4-5] 0D 00 = length 13 + # [6] 02 = data type (normal) + # [7] AA = data header marker + # [8] 03 = target states (moving+still) + # [9-10] 64 00 = moving distance 100 (0x0064) + # [11] 32 = moving energy 50 + # [12-13] 78 00 = still distance 120 (0x0078) + # [14] 19 = still energy 25 + # [15-16] 64 00 = detect distance bytes (ignored by LD2412 code) + # [17] 00 = padding + # [18] 55 = data footer marker + # [19] 00 = CRC/check + # [20-23] F8 F7 F6 F5 = data frame footer + - delay: 100ms + inject_rx: + [ + 0xF4, 0xF3, 0xF2, 0xF1, + 0x0D, 0x00, + 0x02, 0xAA, + 0x03, + 0x64, 0x00, + 0x32, + 0x78, 0x00, + 0x19, + 0x64, 0x00, + 0x00, + 0x55, 0x00, + 0xF8, 0xF7, 0xF6, 0xF5, + ] + + # Phase 2 (t=300ms): Garbage bytes + # LD2412's parser rejects bytes that don't match the frame header at + # position 0 (must start with F4 or FD), so buffer stays empty. + - delay: 200ms + inject_rx: [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x11, 0x22] + + # Phase 3 (t=400ms): Truncated frame (header + partial data, no footer) + # Starts with valid data frame header so parser accepts it. + # After this, buffer_pos_ = 8. + - delay: 100ms + inject_rx: [0xF4, 0xF3, 0xF2, 0xF1, 0x0D, 0x00, 0x02, 0xAA] + + # Phase 4 (t=600ms): Overflow - inject 60 bytes of 0xFF (MAX_LINE_LENGTH=54) + # Buffer has 8 bytes from phase 3 (garbage in phase 2 was rejected). + # Overflow math: buffer_pos_ starts at 8, overflow triggers when + # buffer_pos_ reaches 53 (MAX_LINE_LENGTH - 1). Need 45 more bytes to + # fill positions 8-52, then byte 46 triggers overflow. After overflow, + # buffer_pos_ = 0 and remaining 0xFF bytes are rejected (don't match header). + - delay: 200ms + inject_rx: + [ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ] + + # Phase 5 (t=700ms): Valid frame after overflow - recovery test + # Buffer was reset by overflow. This valid frame should parse correctly. + # Moving target: 50cm, energy 100 + # Still target: 75cm, energy 80 + # detection_distance = 50 (moving target distance, since MOVE_BITMASK set) + - delay: 100ms + inject_rx: + [ + 0xF4, 0xF3, 0xF2, 0xF1, + 0x0D, 0x00, + 0x02, 0xAA, + 0x03, + 0x32, 0x00, + 0x64, + 0x4B, 0x00, + 0x50, + 0x32, 0x00, + 0x00, + 0x55, 0x00, + 0xF8, 0xF7, 0xF6, 0xF5, + ] + +ld2412: + id: ld2412_dev + uart_id: mock_uart + +sensor: + - platform: ld2412 + ld2412_id: ld2412_dev + moving_distance: + name: "Moving Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_distance: + name: "Still Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + moving_energy: + name: "Moving Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_energy: + name: "Still Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + detection_distance: + name: "Detection Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + +binary_sensor: + - platform: ld2412 + ld2412_id: ld2412_dev + has_target: + name: "Has Target" + filters: + - settle: 50ms + has_moving_target: + name: "Has Moving Target" + filters: + - settle: 50ms + has_still_target: + name: "Has Still Target" + filters: + - settle: 50ms diff --git a/tests/integration/fixtures/uart_mock_ld2412_engineering.yaml b/tests/integration/fixtures/uart_mock_ld2412_engineering.yaml new file mode 100644 index 00000000000..3c669fc9a9d --- /dev/null +++ b/tests/integration/fixtures/uart_mock_ld2412_engineering.yaml @@ -0,0 +1,213 @@ +esphome: + name: uart-mock-ld2412-eng-test + +host: +api: +logger: + level: VERBOSE + +external_components: + - source: + type: local + path: EXTERNAL_COMPONENT_PATH + +# Dummy uart entry to satisfy ld2412's DEPENDENCIES = ["uart"] +uart: + baud_rate: 115200 + port: /dev/null + +uart_mock: + id: mock_uart + baud_rate: 256000 + injections: + # Phase 1 (t=100ms): Valid LD2412 engineering mode data frame + # + # Engineering mode frame layout (52 bytes): + # [0-3] F4 F3 F2 F1 = data frame header + # [4-5] 2A 00 = length 42 + # [6] 01 = data type (engineering mode) + # [7] AA = data header marker + # [8] 03 = target states (moving+still) + # [9-10] 1E 00 = moving distance 30 (0x001E) + # [11] 64 = moving energy 100 + # [12-13] 1E 00 = still distance 30 (0x001E) + # [14] 64 = still energy 100 + # [15-16] 00 00 = detection distance bytes (ignored) + # [17-30] gate moving energies (14 gates) + # [31-44] gate still energies (14 gates) + # [45] 57 = light sensor value 87 + # [46] 55 = data footer marker + # [47] 00 = check + # [48-51] F8 F7 F6 F5 = data frame footer + - delay: 100ms + inject_rx: + [ + 0xF4, 0xF3, 0xF2, 0xF1, + 0x2A, 0x00, + 0x01, 0xAA, + 0x03, + 0x1E, 0x00, + 0x64, + 0x1E, 0x00, + 0x64, + 0x00, 0x00, + 0x64, 0x41, 0x06, 0x0E, 0x2B, 0x16, 0x03, 0x03, 0x07, 0x05, 0x09, 0x08, 0x07, 0x06, + 0x00, 0x00, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x50, 0x40, 0x30, 0x20, 0x10, + 0x57, + 0x55, 0x00, + 0xF8, 0xF7, 0xF6, 0xF5, + ] + + # Phase 2 (t=200ms): Second engineering mode frame with different values + # Moving at 73cm, still at 30cm + - delay: 100ms + inject_rx: + [ + 0xF4, 0xF3, 0xF2, 0xF1, + 0x2A, 0x00, + 0x01, 0xAA, + 0x03, + 0x49, 0x00, + 0x64, + 0x1E, 0x00, + 0x64, + 0x21, 0x00, + 0x11, 0x64, 0x05, 0x29, 0x39, 0x10, 0x03, 0x11, 0x0E, 0x08, 0x06, 0x04, 0x03, 0x02, + 0x00, 0x00, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x50, 0x40, 0x30, 0x20, 0x10, + 0x57, + 0x55, 0x00, + 0xF8, 0xF7, 0xF6, 0xF5, + ] + + # Phase 3 (t=300ms): Frame with still target at 291cm (multi-byte distance) + # This tests encode_uint16 with high byte > 0 + # Target state: 0x02 (still only) -> detection_distance = still distance = 291 + - delay: 100ms + inject_rx: + [ + 0xF4, 0xF3, 0xF2, 0xF1, + 0x2A, 0x00, + 0x01, 0xAA, + 0x02, + 0x2F, 0x00, + 0x36, + 0x23, 0x01, + 0x64, + 0x21, 0x00, + 0x2F, 0x36, 0x09, 0x0D, 0x15, 0x0B, 0x06, 0x06, 0x08, 0x09, 0x08, 0x07, 0x06, 0x05, + 0x00, 0x00, 0x64, 0x64, 0x64, 0x64, 0x64, 0x5A, 0x3D, 0x30, 0x20, 0x10, 0x08, 0x04, + 0x57, + 0x55, 0x00, + 0xF8, 0xF7, 0xF6, 0xF5, + ] + +ld2412: + id: ld2412_dev + uart_id: mock_uart + +sensor: + - platform: ld2412 + ld2412_id: ld2412_dev + moving_distance: + name: "Moving Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_distance: + name: "Still Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + moving_energy: + name: "Moving Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_energy: + name: "Still Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + detection_distance: + name: "Detection Distance" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + light: + name: "Light" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + gate_0: + move_energy: + name: "Gate 0 Move Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_energy: + name: "Gate 0 Still Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + gate_1: + move_energy: + name: "Gate 1 Move Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_energy: + name: "Gate 1 Still Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + gate_2: + move_energy: + name: "Gate 2 Move Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + still_energy: + name: "Gate 2 Still Energy" + filters: + - timeout: + timeout: 50ms + value: last + - throttle_with_priority: 50ms + +binary_sensor: + - platform: ld2412 + ld2412_id: ld2412_dev + has_target: + name: "Has Target" + filters: + - settle: 50ms + has_moving_target: + name: "Has Moving Target" + filters: + - settle: 50ms + has_still_target: + name: "Has Still Target" + filters: + - settle: 50ms diff --git a/tests/integration/test_uart_mock_ld2412.py b/tests/integration/test_uart_mock_ld2412.py new file mode 100644 index 00000000000..cf7324ceed3 --- /dev/null +++ b/tests/integration/test_uart_mock_ld2412.py @@ -0,0 +1,407 @@ +"""Integration test for LD2412 component with mock UART. + +Tests: +test_uart_mock_ld2412 (normal mode): + 1. Happy path - valid data frame publishes correct sensor values + 2. Garbage resilience - random bytes don't crash the component + 3. Truncated frame handling - partial frame doesn't corrupt state + 4. Buffer overflow recovery - overflow resets the parser + 5. Post-overflow parsing - next valid frame after overflow is parsed correctly + 6. TX logging - verifies LD2412 sends expected setup commands + +test_uart_mock_ld2412_engineering (engineering mode): + 1. Engineering mode frames with per-gate energy data and light sensor + 2. Multi-byte still distance (291cm) using high byte > 0 + 3. Gate energy sensor values + 4. Detection distance computed from target state +""" + +from __future__ import annotations + +import asyncio +from pathlib import Path + +from aioesphomeapi import ( + BinarySensorInfo, + BinarySensorState, + EntityState, + SensorInfo, + SensorState, +) +import pytest + +from .state_utils import InitialStateHelper, build_key_to_entity_mapping, find_entity +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_uart_mock_ld2412( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test LD2412 data parsing with happy path, garbage, overflow, and recovery.""" + # Replace external component path placeholder + external_components_path = str( + Path(__file__).parent / "fixtures" / "external_components" + ) + yaml_config = yaml_config.replace( + "EXTERNAL_COMPONENT_PATH", external_components_path + ) + + loop = asyncio.get_running_loop() + + # Track overflow warning in logs + overflow_seen = loop.create_future() + + # Track TX data logged by the mock for assertions + tx_log_lines: list[str] = [] + + def line_callback(line: str) -> None: + if "Max command length exceeded" in line and not overflow_seen.done(): + overflow_seen.set_result(True) + # Capture all TX log lines from uart_mock + if "uart_mock" in line and "TX " in line: + tx_log_lines.append(line) + + # Track sensor state updates (after initial state is swallowed) + sensor_states: dict[str, list[float]] = { + "moving_distance": [], + "still_distance": [], + "moving_energy": [], + "still_energy": [], + "detection_distance": [], + } + binary_states: dict[str, list[bool]] = { + "has_target": [], + "has_moving_target": [], + "has_still_target": [], + } + + # Signal when we see recovery frame values + recovery_received = loop.create_future() + + def on_state(state: EntityState) -> None: + if isinstance(state, SensorState) and not state.missing_state: + sensor_name = key_to_sensor.get(state.key) + if sensor_name and sensor_name in sensor_states: + sensor_states[sensor_name].append(state.state) + # Check if this is the recovery frame (moving_distance = 50) + if ( + sensor_name == "moving_distance" + and state.state == pytest.approx(50.0) + and not recovery_received.done() + ): + recovery_received.set_result(True) + elif isinstance(state, BinarySensorState): + sensor_name = key_to_sensor.get(state.key) + if sensor_name and sensor_name in binary_states: + binary_states[sensor_name].append(state.state) + + async with ( + run_compiled(yaml_config, line_callback=line_callback), + api_client_connected() as client, + ): + entities, _ = await client.list_entities_services() + + # Build key mappings for all sensor types + all_names = list(sensor_states.keys()) + list(binary_states.keys()) + # Sort by descending length to avoid substring collisions + # (e.g., "still_energy" matching "gate_0_still_energy") + all_names.sort(key=len, reverse=True) + key_to_sensor = build_key_to_entity_mapping(entities, all_names) + + # Set up initial state helper + initial_state_helper = InitialStateHelper(entities) + client.subscribe_states(initial_state_helper.on_state_wrapper(on_state)) + + try: + await initial_state_helper.wait_for_initial_states() + except TimeoutError: + pytest.fail("Timeout waiting for initial states") + + # Phase 1 values are in the initial states (swallowed by InitialStateHelper). + # Verify them via initial_states dict. + moving_dist_entity = find_entity(entities, "moving_distance", SensorInfo) + assert moving_dist_entity is not None + initial_moving = initial_state_helper.initial_states.get(moving_dist_entity.key) + assert initial_moving is not None and isinstance(initial_moving, SensorState) + assert initial_moving.state == pytest.approx(100.0), ( + f"Initial moving distance should be 100, got {initial_moving.state}" + ) + + still_dist_entity = find_entity(entities, "still_distance", SensorInfo) + assert still_dist_entity is not None + initial_still = initial_state_helper.initial_states.get(still_dist_entity.key) + assert initial_still is not None and isinstance(initial_still, SensorState) + assert initial_still.state == pytest.approx(120.0), ( + f"Initial still distance should be 120, got {initial_still.state}" + ) + + moving_energy_entity = find_entity(entities, "moving_energy", SensorInfo) + assert moving_energy_entity is not None + initial_me = initial_state_helper.initial_states.get(moving_energy_entity.key) + assert initial_me is not None and isinstance(initial_me, SensorState) + assert initial_me.state == pytest.approx(50.0), ( + f"Initial moving energy should be 50, got {initial_me.state}" + ) + + still_energy_entity = find_entity(entities, "still_energy", SensorInfo) + assert still_energy_entity is not None + initial_se = initial_state_helper.initial_states.get(still_energy_entity.key) + assert initial_se is not None and isinstance(initial_se, SensorState) + assert initial_se.state == pytest.approx(25.0), ( + f"Initial still energy should be 25, got {initial_se.state}" + ) + + # LD2412 detection_distance = moving_distance when MOVE_BITMASK is set + detect_dist_entity = find_entity(entities, "detection_distance", SensorInfo) + assert detect_dist_entity is not None + initial_dd = initial_state_helper.initial_states.get(detect_dist_entity.key) + assert initial_dd is not None and isinstance(initial_dd, SensorState) + assert initial_dd.state == pytest.approx(100.0), ( + f"Initial detection distance should be 100, got {initial_dd.state}" + ) + + # Wait for the recovery frame (Phase 5) to be parsed + # This proves the component survived garbage + truncated + overflow + try: + await asyncio.wait_for(recovery_received, timeout=3.0) + except TimeoutError: + pytest.fail( + f"Timeout waiting for recovery frame. Received sensor states:\n" + f" moving_distance: {sensor_states['moving_distance']}\n" + f" still_distance: {sensor_states['still_distance']}\n" + f" moving_energy: {sensor_states['moving_energy']}\n" + f" still_energy: {sensor_states['still_energy']}\n" + f" detection_distance: {sensor_states['detection_distance']}" + ) + + # Verify overflow warning was logged + assert overflow_seen.done(), ( + "Expected 'Max command length exceeded' warning in logs" + ) + + # Verify LD2412 sent setup commands (TX logging) + assert len(tx_log_lines) > 0, "Expected TX log lines from uart_mock" + tx_data = " ".join(tx_log_lines) + # Verify command frame header appears (FD:FC:FB:FA) + assert "FD:FC:FB:FA" in tx_data, ( + "Expected LD2412 command frame header FD:FC:FB:FA in TX log" + ) + # Verify command frame footer appears (04:03:02:01) + assert "04:03:02:01" in tx_data, ( + "Expected LD2412 command frame footer 04:03:02:01 in TX log" + ) + + # Recovery frame values (Phase 5, after overflow) + assert len(sensor_states["moving_distance"]) >= 1, ( + f"Expected recovery moving_distance, got: {sensor_states['moving_distance']}" + ) + # Find the recovery value (moving_distance = 50) + recovery_values = [ + v for v in sensor_states["moving_distance"] if v == pytest.approx(50.0) + ] + assert len(recovery_values) >= 1, ( + f"Expected moving_distance=50 in recovery, got: {sensor_states['moving_distance']}" + ) + + # Recovery frame: moving=50, still=75, energy=100/80, detect=50 + recovery_idx = next( + i + for i, v in enumerate(sensor_states["moving_distance"]) + if v == pytest.approx(50.0) + ) + assert sensor_states["still_distance"][recovery_idx] == pytest.approx(75.0), ( + f"Recovery still distance should be 75, got {sensor_states['still_distance'][recovery_idx]}" + ) + assert sensor_states["moving_energy"][recovery_idx] == pytest.approx(100.0), ( + f"Recovery moving energy should be 100, got {sensor_states['moving_energy'][recovery_idx]}" + ) + assert sensor_states["still_energy"][recovery_idx] == pytest.approx(80.0), ( + f"Recovery still energy should be 80, got {sensor_states['still_energy'][recovery_idx]}" + ) + # LD2412 detection_distance = moving_distance when MOVE_BITMASK set + assert sensor_states["detection_distance"][recovery_idx] == pytest.approx( + 50.0 + ), ( + f"Recovery detection distance should be 50, got {sensor_states['detection_distance'][recovery_idx]}" + ) + + # Verify binary sensors detected targets + has_target_entity = find_entity(entities, "has_target", BinarySensorInfo) + assert has_target_entity is not None + initial_ht = initial_state_helper.initial_states.get(has_target_entity.key) + assert initial_ht is not None and isinstance(initial_ht, BinarySensorState) + assert initial_ht.state is True, "Has target should be True" + + has_moving_entity = find_entity(entities, "has_moving_target", BinarySensorInfo) + assert has_moving_entity is not None + initial_hm = initial_state_helper.initial_states.get(has_moving_entity.key) + assert initial_hm is not None and isinstance(initial_hm, BinarySensorState) + assert initial_hm.state is True, "Has moving target should be True" + + has_still_entity = find_entity(entities, "has_still_target", BinarySensorInfo) + assert has_still_entity is not None + initial_hs = initial_state_helper.initial_states.get(has_still_entity.key) + assert initial_hs is not None and isinstance(initial_hs, BinarySensorState) + assert initial_hs.state is True, "Has still target should be True" + + +@pytest.mark.asyncio +async def test_uart_mock_ld2412_engineering( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test LD2412 engineering mode with per-gate energy, light, and multi-byte distance.""" + external_components_path = str( + Path(__file__).parent / "fixtures" / "external_components" + ) + yaml_config = yaml_config.replace( + "EXTERNAL_COMPONENT_PATH", external_components_path + ) + + loop = asyncio.get_running_loop() + + # Track sensor state updates (after initial state is swallowed) + sensor_states: dict[str, list[float]] = { + "moving_distance": [], + "still_distance": [], + "moving_energy": [], + "still_energy": [], + "detection_distance": [], + "light": [], + "gate_0_move_energy": [], + "gate_1_move_energy": [], + "gate_2_move_energy": [], + "gate_0_still_energy": [], + "gate_1_still_energy": [], + "gate_2_still_energy": [], + } + binary_states: dict[str, list[bool]] = { + "has_target": [], + "has_moving_target": [], + "has_still_target": [], + } + + # Signal when we see Phase 3 frame values + phase3_still_received = loop.create_future() + phase3_detect_received = loop.create_future() + + def on_state(state: EntityState) -> None: + if isinstance(state, SensorState) and not state.missing_state: + sensor_name = key_to_sensor.get(state.key) + if sensor_name and sensor_name in sensor_states: + sensor_states[sensor_name].append(state.state) + if ( + sensor_name == "still_distance" + and state.state == pytest.approx(291.0) + and not phase3_still_received.done() + ): + phase3_still_received.set_result(True) + if ( + sensor_name == "detection_distance" + and state.state == pytest.approx(291.0) + and not phase3_detect_received.done() + ): + phase3_detect_received.set_result(True) + elif isinstance(state, BinarySensorState): + sensor_name = key_to_sensor.get(state.key) + if sensor_name and sensor_name in binary_states: + binary_states[sensor_name].append(state.state) + + async with ( + run_compiled(yaml_config), + api_client_connected() as client, + ): + entities, _ = await client.list_entities_services() + + all_names = list(sensor_states.keys()) + list(binary_states.keys()) + # Sort by descending length to avoid substring collisions + # (e.g., "still_energy" matching "gate_0_still_energy") + all_names.sort(key=len, reverse=True) + key_to_sensor = build_key_to_entity_mapping(entities, all_names) + + initial_state_helper = InitialStateHelper(entities) + client.subscribe_states(initial_state_helper.on_state_wrapper(on_state)) + + try: + await initial_state_helper.wait_for_initial_states() + except TimeoutError: + pytest.fail("Timeout waiting for initial states") + + # Phase 1 initial values (engineering mode frame): + # moving=30, energy=100, still=30, energy=100, detect=30 + moving_dist_entity = find_entity(entities, "moving_distance", SensorInfo) + assert moving_dist_entity is not None + initial_moving = initial_state_helper.initial_states.get(moving_dist_entity.key) + assert initial_moving is not None and isinstance(initial_moving, SensorState) + assert initial_moving.state == pytest.approx(30.0), ( + f"Initial moving distance should be 30, got {initial_moving.state}" + ) + + still_dist_entity = find_entity(entities, "still_distance", SensorInfo) + assert still_dist_entity is not None + initial_still = initial_state_helper.initial_states.get(still_dist_entity.key) + assert initial_still is not None and isinstance(initial_still, SensorState) + assert initial_still.state == pytest.approx(30.0), ( + f"Initial still distance should be 30, got {initial_still.state}" + ) + + # Verify engineering mode sensors from initial state + # Gate 0 moving energy = 0x64 = 100 + gate0_move_entity = find_entity(entities, "gate_0_move_energy", SensorInfo) + assert gate0_move_entity is not None + initial_g0m = initial_state_helper.initial_states.get(gate0_move_entity.key) + assert initial_g0m is not None and isinstance(initial_g0m, SensorState) + assert initial_g0m.state == pytest.approx(100.0), ( + f"Gate 0 move energy should be 100, got {initial_g0m.state}" + ) + + # Gate 1 moving energy = 0x41 = 65 + gate1_move_entity = find_entity(entities, "gate_1_move_energy", SensorInfo) + assert gate1_move_entity is not None + initial_g1m = initial_state_helper.initial_states.get(gate1_move_entity.key) + assert initial_g1m is not None and isinstance(initial_g1m, SensorState) + assert initial_g1m.state == pytest.approx(65.0), ( + f"Gate 1 move energy should be 65, got {initial_g1m.state}" + ) + + # Light sensor = 0x57 = 87 + light_entity = find_entity(entities, "light", SensorInfo) + assert light_entity is not None + initial_light = initial_state_helper.initial_states.get(light_entity.key) + assert initial_light is not None and isinstance(initial_light, SensorState) + assert initial_light.state == pytest.approx(87.0), ( + f"Light sensor should be 87, got {initial_light.state}" + ) + + # Wait for Phase 3 frame: still_distance = 291cm (multi-byte) + try: + await asyncio.wait_for(phase3_still_received, timeout=3.0) + except TimeoutError: + pytest.fail( + f"Timeout waiting for Phase 3 still_distance. Received:\n" + f" still_distance: {sensor_states['still_distance']}\n" + f" moving_distance: {sensor_states['moving_distance']}" + ) + + assert pytest.approx(291.0) in sensor_states["still_distance"], ( + f"Expected still_distance=291, got: {sensor_states['still_distance']}" + ) + + # Wait for Phase 3: detection_distance = 291 (still-only target) + # target_state=0x02 so LD2412 uses still_distance for detection_distance. + # The throttle_with_priority filter may delay this value. + try: + await asyncio.wait_for(phase3_detect_received, timeout=3.0) + except TimeoutError: + pytest.fail( + f"Timeout waiting for detection_distance=291 (still-only target). " + f"Received: {sensor_states['detection_distance']}" + ) + + assert pytest.approx(291.0) in sensor_states["detection_distance"], ( + f"Expected detection_distance=291, got: {sensor_states['detection_distance']}" + ) From a1df4f80e13460612c141e7abf142e94c3f0a59e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 07:24:59 -1000 Subject: [PATCH 32/42] Skip proto message dump for log and camera responses In debug builds (HAS_PROTO_MESSAGE_DUMP), skip dump logging for SubscribeLogsResponse (recursive logging risk) and CameraImageResponse (high-frequency image data noise). This matches the base branch behavior where both bypassed dump logging via direct send_message_impl() calls. --- esphome/components/api/api_connection.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index ff3a3771c9f..4345e5acf79 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1869,7 +1869,12 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) { bool APIConnection::send_message_(uint32_t payload_size, uint8_t message_type, MessageEncodeFn encode_fn, const void *msg) { #ifdef HAS_PROTO_MESSAGE_DUMP - { + // Skip dump for log messages (recursive logging risk) and camera frames (high-frequency noise) + if (message_type != SubscribeLogsResponse::MESSAGE_TYPE +#ifdef USE_CAMERA + && message_type != CameraImageResponse::MESSAGE_TYPE +#endif + ) { auto *proto_msg = static_cast(msg); DumpBuffer dump_buf; this->log_send_message_(proto_msg->message_name(), proto_msg->dump_to(dump_buf)); From 5ba880f19b967b153340befa1acf271066f8671c Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:57:45 -0500 Subject: [PATCH 33/42] [sx127x] Fix preamble MSB register always written as zero (#14457) Co-authored-by: Claude Opus 4.6 --- esphome/components/sx127x/sx127x.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/sx127x/sx127x.cpp b/esphome/components/sx127x/sx127x.cpp index caf68b6d513..f6aa11b6347 100644 --- a/esphome/components/sx127x/sx127x.cpp +++ b/esphome/components/sx127x/sx127x.cpp @@ -186,7 +186,7 @@ void SX127x::configure_fsk_ook_() { } else { this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_OFF); } - this->write_register_(REG_PREAMBLE_SIZE_MSB, this->preamble_size_ >> 16); + this->write_register_(REG_PREAMBLE_SIZE_MSB, this->preamble_size_ >> 8); this->write_register_(REG_PREAMBLE_SIZE_LSB, this->preamble_size_ & 0xFF); // config sync generation and setup ook threshold @@ -214,7 +214,7 @@ void SX127x::configure_lora_() { // config preamble if (this->preamble_size_ >= 6) { - this->write_register_(REG_PREAMBLE_LEN_MSB, this->preamble_size_ >> 16); + this->write_register_(REG_PREAMBLE_LEN_MSB, this->preamble_size_ >> 8); this->write_register_(REG_PREAMBLE_LEN_LSB, this->preamble_size_ & 0xFF); } From 9abba79c5429ee9c9c4e9a4f77ca4c67b4a756b2 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:58:24 -0500 Subject: [PATCH 34/42] [remote_base][remote_receiver] Fix OOB access in pronto comparison and RMT buffer allocation (#14459) Co-authored-by: Claude Opus 4.6 --- esphome/components/remote_base/pronto_protocol.cpp | 6 +++++- esphome/components/remote_receiver/remote_receiver_rmt.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 43029cbc2fc..6903cd46058 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -44,9 +44,13 @@ bool ProntoData::operator==(const ProntoData &rhs) const { std::vector data1 = encode_pronto(data); std::vector data2 = encode_pronto(rhs.data); + if (data1.size() != data2.size() || data1.empty()) { + return false; + } + uint32_t total_diff = 0; // Don't need to check the last one, it's the large gap at the end. - for (std::vector::size_type i = 0; i < data1.size() - 1; ++i) { + for (size_t i = 0; i < data1.size() - 1; ++i) { int diff = data2[i] - data1[i]; diff *= diff; if (rhs.delta == -1 && diff > 9) diff --git a/esphome/components/remote_receiver/remote_receiver_rmt.cpp b/esphome/components/remote_receiver/remote_receiver_rmt.cpp index 357a36d052f..96b23bd0f52 100644 --- a/esphome/components/remote_receiver/remote_receiver_rmt.cpp +++ b/esphome/components/remote_receiver/remote_receiver_rmt.cpp @@ -106,7 +106,7 @@ void RemoteReceiverComponent::setup() { this->store_.filter_symbols = this->filter_symbols_; this->store_.receive_size = this->receive_symbols_ * sizeof(rmt_symbol_word_t); this->store_.buffer_size = std::max((event_size + this->store_.receive_size) * 2, this->buffer_size_); - this->store_.buffer = new uint8_t[this->buffer_size_]; + this->store_.buffer = new uint8_t[this->store_.buffer_size]; error = rmt_receive(this->channel_, (uint8_t *) this->store_.buffer + event_size, this->store_.receive_size, &this->store_.config); if (error != ESP_OK) { From 246a8bff0cb9c2de5a740fe8529f072c609dce51 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:58:42 -0500 Subject: [PATCH 35/42] [pn7160][pn7150][pn532] Fix tag purge skipping, NDEF bounds check, and NDEF length byte order (#14460) Co-authored-by: Claude Opus 4.6 --- esphome/components/pn532/pn532_mifare_ultralight.cpp | 4 ++-- esphome/components/pn7150/pn7150.cpp | 6 +++--- esphome/components/pn7150/pn7150_mifare_ultralight.cpp | 4 ++-- esphome/components/pn7160/pn7160.cpp | 6 +++--- esphome/components/pn7160/pn7160_mifare_ultralight.cpp | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/esphome/components/pn532/pn532_mifare_ultralight.cpp b/esphome/components/pn532/pn532_mifare_ultralight.cpp index a8a8e2d5735..0e0dc1542f4 100644 --- a/esphome/components/pn532/pn532_mifare_ultralight.cpp +++ b/esphome/components/pn532/pn532_mifare_ultralight.cpp @@ -99,7 +99,7 @@ bool PN532::find_mifare_ultralight_ndef_(const std::vector &page_3_to_6 uint8_t &message_start_index) { const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector - if (!(page_3_to_6.size() > p4_offset + 5)) { + if (!(page_3_to_6.size() > p4_offset + 6)) { return false; } @@ -134,7 +134,7 @@ bool PN532::write_mifare_ultralight_tag_(nfc::NfcTagUid &uid, nfc::NdefMessage * } else { encoded.insert(encoded.begin() + 1, 0xFF); encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF); - encoded.insert(encoded.begin() + 2, message_length & 0xFF); + encoded.insert(encoded.begin() + 3, message_length & 0xFF); } encoded.push_back(0xFE); diff --git a/esphome/components/pn7150/pn7150.cpp b/esphome/components/pn7150/pn7150.cpp index 8c76c8b88c9..d68bea41b3d 100644 --- a/esphome/components/pn7150/pn7150.cpp +++ b/esphome/components/pn7150/pn7150.cpp @@ -562,9 +562,9 @@ optional PN7150::find_tag_uid_(const nfc::NfcTagUid &uid) { } void PN7150::purge_old_tags_() { - for (size_t i = 0; i < this->discovered_endpoint_.size(); i++) { - if (millis() - this->discovered_endpoint_[i].last_seen > this->tag_ttl_) { - this->erase_tag_(i); + for (size_t i = this->discovered_endpoint_.size(); i > 0; i--) { + if (millis() - this->discovered_endpoint_[i - 1].last_seen > this->tag_ttl_) { + this->erase_tag_(i - 1); } } } diff --git a/esphome/components/pn7150/pn7150_mifare_ultralight.cpp b/esphome/components/pn7150/pn7150_mifare_ultralight.cpp index 46f5dba2b76..854ddd1be18 100644 --- a/esphome/components/pn7150/pn7150_mifare_ultralight.cpp +++ b/esphome/components/pn7150/pn7150_mifare_ultralight.cpp @@ -100,7 +100,7 @@ uint8_t PN7150::find_mifare_ultralight_ndef_(const std::vector &page_3_ uint8_t &message_start_index) { const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector - if (!(page_3_to_6.size() > p4_offset + 5)) { + if (!(page_3_to_6.size() > p4_offset + 6)) { return nfc::STATUS_FAILED; } @@ -135,7 +135,7 @@ uint8_t PN7150::write_mifare_ultralight_tag_(nfc::NfcTagUid &uid, const std::sha } else { encoded.insert(encoded.begin() + 1, 0xFF); encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF); - encoded.insert(encoded.begin() + 2, message_length & 0xFF); + encoded.insert(encoded.begin() + 3, message_length & 0xFF); } encoded.push_back(0xFE); diff --git a/esphome/components/pn7160/pn7160.cpp b/esphome/components/pn7160/pn7160.cpp index 3fcd1221a72..5f0f8d0629c 100644 --- a/esphome/components/pn7160/pn7160.cpp +++ b/esphome/components/pn7160/pn7160.cpp @@ -589,9 +589,9 @@ optional PN7160::find_tag_uid_(const nfc::NfcTagUid &uid) { } void PN7160::purge_old_tags_() { - for (size_t i = 0; i < this->discovered_endpoint_.size(); i++) { - if (millis() - this->discovered_endpoint_[i].last_seen > this->tag_ttl_) { - this->erase_tag_(i); + for (size_t i = this->discovered_endpoint_.size(); i > 0; i--) { + if (millis() - this->discovered_endpoint_[i - 1].last_seen > this->tag_ttl_) { + this->erase_tag_(i - 1); } } } diff --git a/esphome/components/pn7160/pn7160_mifare_ultralight.cpp b/esphome/components/pn7160/pn7160_mifare_ultralight.cpp index 9dc8d3dd2d5..8ca0fa2c11b 100644 --- a/esphome/components/pn7160/pn7160_mifare_ultralight.cpp +++ b/esphome/components/pn7160/pn7160_mifare_ultralight.cpp @@ -100,7 +100,7 @@ uint8_t PN7160::find_mifare_ultralight_ndef_(const std::vector &page_3_ uint8_t &message_start_index) { const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector - if (!(page_3_to_6.size() > p4_offset + 5)) { + if (!(page_3_to_6.size() > p4_offset + 6)) { return nfc::STATUS_FAILED; } @@ -135,7 +135,7 @@ uint8_t PN7160::write_mifare_ultralight_tag_(nfc::NfcTagUid &uid, const std::sha } else { encoded.insert(encoded.begin() + 1, 0xFF); encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF); - encoded.insert(encoded.begin() + 2, message_length & 0xFF); + encoded.insert(encoded.begin() + 3, message_length & 0xFF); } encoded.push_back(0xFE); From c37ab1de841631dd1802a2abbfde655f49513e12 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:58:52 -0500 Subject: [PATCH 36/42] [fingerprint_grow] Fix OOB write and uint16 overflow (#14462) Co-authored-by: Claude Opus 4.6 --- .../fingerprint_grow/fingerprint_grow.cpp | 23 ++++++++++--------- .../fingerprint_grow/fingerprint_grow.h | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index da4535fc828..a633fbca282 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -361,7 +361,7 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui } } -uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) { +uint8_t FingerprintGrowComponent::transfer_(std::vector &data_buffer) { while (this->available()) this->read(); this->write((uint8_t) (START_CODE >> 8)); @@ -372,12 +372,12 @@ uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) this->write(this->address_[3]); this->write(COMMAND); - uint16_t wire_length = p_data_buffer->size() + 2; + uint16_t wire_length = data_buffer.size() + 2; this->write((uint8_t) (wire_length >> 8)); this->write((uint8_t) (wire_length & 0xFF)); uint16_t sum = (wire_length >> 8) + (wire_length & 0xFF) + COMMAND; - for (auto data : *p_data_buffer) { + for (auto data : data_buffer) { this->write(data); sum += data; } @@ -385,7 +385,7 @@ uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) this->write((uint8_t) (sum >> 8)); this->write((uint8_t) (sum & 0xFF)); - p_data_buffer->clear(); + data_buffer.clear(); uint8_t byte; uint16_t idx = 0, length = 0; @@ -431,9 +431,9 @@ uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) length |= byte; break; default: - p_data_buffer->push_back(byte); + data_buffer.push_back(byte); if ((idx - 8) == length) { - switch ((*p_data_buffer)[0]) { + switch (data_buffer[0]) { case OK: case NO_FINGER: case IMAGE_FAIL: @@ -453,25 +453,26 @@ uint8_t FingerprintGrowComponent::transfer_(std::vector *p_data_buffer) ESP_LOGE(TAG, "Reader failed to process request"); break; default: - ESP_LOGE(TAG, "Unknown response received from reader: 0x%.2X", (*p_data_buffer)[0]); + ESP_LOGE(TAG, "Unknown response received from reader: 0x%.2X", data_buffer[0]); break; } this->last_transfer_ms_ = millis(); - return (*p_data_buffer)[0]; + return data_buffer[0]; } break; } idx++; } ESP_LOGE(TAG, "No response received from reader"); - (*p_data_buffer)[0] = TIMEOUT; + data_buffer.clear(); + data_buffer.push_back(TIMEOUT); this->last_transfer_ms_ = millis(); return TIMEOUT; } uint8_t FingerprintGrowComponent::send_command_() { this->sensor_wakeup_(); - return this->transfer_(&this->data_); + return this->transfer_(this->data_); } void FingerprintGrowComponent::sensor_wakeup_() { @@ -517,7 +518,7 @@ void FingerprintGrowComponent::sensor_wakeup_() { std::vector buffer = {VERIFY_PASSWORD, (uint8_t) (this->password_ >> 24), (uint8_t) (this->password_ >> 16), (uint8_t) (this->password_ >> 8), (uint8_t) (this->password_ & 0xFF)}; - if (this->transfer_(&buffer) != OK) { + if (this->transfer_(buffer) != OK) { ESP_LOGE(TAG, "Wrong password"); } } diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.h b/esphome/components/fingerprint_grow/fingerprint_grow.h index 370b26f56a3..db9d5ce564f 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.h +++ b/esphome/components/fingerprint_grow/fingerprint_grow.h @@ -169,7 +169,7 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic bool set_password_(); bool get_parameters_(); void get_fingerprint_count_(); - uint8_t transfer_(std::vector *p_data_buffer); + uint8_t transfer_(std::vector &data_buffer); uint8_t send_command_(); void sensor_wakeup_(); void sensor_sleep_(); @@ -190,7 +190,7 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic bool is_sensor_awake_ = false; uint32_t last_transfer_ms_ = 0; uint32_t last_aura_led_control_ = 0; - uint16_t last_aura_led_duration_ = 0; + uint32_t last_aura_led_duration_ = 0; uint16_t system_identifier_code_ = 0; uint32_t idle_period_to_sleep_ms_ = UINT32_MAX; sensor::Sensor *fingerprint_count_sensor_{nullptr}; From d178499c28fbb096846132b87a9a15e44584b9d6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 08:08:58 -1000 Subject: [PATCH 37/42] [wifi] Cache is_connected() for cheap inline access Move is_connected() to the header as an inline method that returns a cached bool field. The previous implementation called wifi_sta_connect_status_() on every invocation, which makes SDK calls on ESP8266 (wifi_station_get_connect_status) and RP2040 (cyw43_wifi_link_status + WiFi.status), preventing inlining and adding overhead for the many callers that check it every loop iteration (network::is_connected, API server, MQTT, status sensor, etc.). The cached state is updated once per loop() after wifi_loop_() processes platform events. Internal call sites that need a live SDK query (STA_CONNECTED loss detection, RP2040 can_proceed) use the new is_connected_() private method directly. --- esphome/components/wifi/wifi_component.cpp | 13 ++++++++++--- esphome/components/wifi/wifi_component.h | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 852ff922f1f..eab16520821 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -725,6 +725,7 @@ void WiFiComponent::restart_adapter() { void WiFiComponent::loop() { this->wifi_loop_(); const uint32_t now = App.get_loop_component_start_time(); + this->update_connected_state_(); if (this->has_sta()) { #if defined(USE_WIFI_CONNECT_TRIGGER) || defined(USE_WIFI_DISCONNECT_TRIGGER) @@ -776,7 +777,7 @@ void WiFiComponent::loop() { } case WIFI_COMPONENT_STATE_STA_CONNECTED: { - if (!this->is_connected()) { + if (!this->is_connected_()) { ESP_LOGW(TAG, "Connection lost; reconnecting"); this->state_ = WIFI_COMPONENT_STATE_STA_CONNECTING; this->retry_connect(); @@ -2118,15 +2119,21 @@ bool WiFiComponent::can_proceed() { if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED || this->ap_setup_) { return true; } - return this->is_connected(); + return this->is_connected_(); } #endif void WiFiComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; } -bool WiFiComponent::is_connected() const { +bool WiFiComponent::is_connected_() const { return this->state_ == WIFI_COMPONENT_STATE_STA_CONNECTED && this->wifi_sta_connect_status_() == WiFiSTAConnectStatus::CONNECTED && !this->error_from_callback_; } +void WiFiComponent::update_connected_state_() { + bool connected = this->is_connected_(); + if (connected != this->connected_) { + this->connected_ = connected; + } +} void WiFiComponent::set_power_save_mode(WiFiPowerSaveMode power_save) { this->power_save_ = power_save; #if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE) diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index a6f03a08d9d..f340b708c90 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -443,7 +443,7 @@ class WiFiComponent : public Component { void set_reboot_timeout(uint32_t reboot_timeout); - bool is_connected() const; + bool is_connected() const { return this->connected_; } void set_power_save_mode(WiFiPowerSaveMode power_save); void set_min_auth_mode(WifiMinAuthMode min_auth_mode) { min_auth_mode_ = min_auth_mode; } @@ -678,6 +678,8 @@ class WiFiComponent : public Component { bool wifi_sta_connect_(const WiFiAP &ap); void wifi_pre_setup_(); WiFiSTAConnectStatus wifi_sta_connect_status_() const; + bool is_connected_() const; + void update_connected_state_(); bool wifi_scan_start_(bool passive); #ifdef USE_WIFI_AP @@ -854,6 +856,7 @@ class WiFiComponent : public Component { bool has_completed_scan_after_captive_portal_start_{ false}; // Tracks if we've completed a scan after captive portal started bool skip_cooldown_next_cycle_{false}; + bool connected_{false}; bool post_connect_roaming_{true}; // Enabled by default #if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE) bool is_high_performance_mode_{false}; From 22fc3aab392c8cad0c2d8a74e6074b83e7c17139 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:19:46 -0500 Subject: [PATCH 38/42] [ld2420] Fix buffer overflows in simple mode, energy mode, and calibration (#14458) Co-authored-by: Claude Opus 4.6 --- esphome/components/ld2420/ld2420.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index f14400d15a4..1e671363c9d 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -460,6 +460,10 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) { uint8_t index = 6; // Start at presence byte position uint16_t range; const uint8_t elements = sizeof(this->gate_energy_) / sizeof(this->gate_energy_[0]); + if (len < static_cast(index + 1 + sizeof(range) + elements * sizeof(this->gate_energy_[0]))) { + ESP_LOGW(TAG, "Energy frame too short: %d bytes", len); + return; + } this->set_presence_(buffer[index]); index++; memcpy(&range, &buffer[index], sizeof(range)); @@ -471,8 +475,11 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) { } if (this->current_operating_mode == OP_CALIBRATE_MODE) { - this->update_radar_data(gate_energy_, sample_number_counter); - this->sample_number_counter > CALIBRATE_SAMPLES ? this->sample_number_counter = 0 : this->sample_number_counter++; + this->update_radar_data(gate_energy_, this->sample_number_counter); + this->sample_number_counter++; + if (this->sample_number_counter >= CALIBRATE_SAMPLES) { + this->sample_number_counter = 0; + } } // Resonable refresh rate for home assistant database size health @@ -503,22 +510,20 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) { char *endptr{nullptr}; char outbuf[bufsize]{0}; while (true) { - if (inbuf[pos - 2] == 'O' && inbuf[pos - 1] == 'F' && inbuf[pos] == 'F') { + if (pos >= 2 && inbuf[pos - 2] == 'O' && inbuf[pos - 1] == 'F' && inbuf[pos] == 'F') { this->set_presence_(false); - } else if (inbuf[pos - 1] == 'O' && inbuf[pos] == 'N') { + } else if (pos >= 1 && inbuf[pos - 1] == 'O' && inbuf[pos] == 'N') { this->set_presence_(true); } if (inbuf[pos] >= '0' && inbuf[pos] <= '9') { if (index < bufsize - 1) { outbuf[index++] = inbuf[pos]; - pos++; } + } + if (pos < len - 1) { + pos++; } else { - if (pos < len - 1) { - pos++; - } else { - break; - } + break; } } outbuf[index] = '\0'; From 30d7834fa8b123a471c867313fbaa42dc1583eb3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 09:13:53 -1000 Subject: [PATCH 39/42] [api] Devirtualize frame helper calls when protocol is fixed at compile time When only one API protocol is configured (plaintext-only or noise-only), use the concrete frame helper type in unique_ptr instead of the base class. Since both APIPlaintextFrameHelper and APINoiseFrameHelper are marked final, the compiler can devirtualize all virtual calls (read_packet, write_protobuf_packet, loop, etc.), eliminating vtable dispatch overhead in the hot APIConnection::loop() path. When both protocols are enabled (encryption key set with plaintext fallback), the polymorphic base pointer is used as before. --- esphome/components/api/api_connection.cpp | 5 +++-- esphome/components/api/api_connection.h | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 59476fac253..98ba1abe0b5 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -114,9 +114,10 @@ APIConnection::APIConnection(std::unique_ptr sock, APIServer *pa this->helper_ = std::unique_ptr{new APIPlaintextFrameHelper(std::move(sock))}; } #elif defined(USE_API_PLAINTEXT) - this->helper_ = std::unique_ptr{new APIPlaintextFrameHelper(std::move(sock))}; + this->helper_ = std::unique_ptr{new APIPlaintextFrameHelper(std::move(sock))}; #elif defined(USE_API_NOISE) - this->helper_ = std::unique_ptr{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())}; + this->helper_ = + std::unique_ptr{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())}; #else #error "No frame helper defined" #endif diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 37855b2482a..aae8db3c688 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -3,6 +3,12 @@ #include "esphome/core/defines.h" #ifdef USE_API #include "api_frame_helper.h" +#ifdef USE_API_NOISE +#include "api_frame_helper_noise.h" +#endif +#ifdef USE_API_PLAINTEXT +#include "api_frame_helper_plaintext.h" +#endif #include "api_pb2.h" #include "api_pb2_service.h" #include "api_server.h" @@ -489,7 +495,13 @@ class APIConnection final : public APIServerConnectionBase { // === Optimal member ordering for 32-bit systems === // Group 1: Pointers (4 bytes each on 32-bit) +#if defined(USE_API_NOISE) && defined(USE_API_PLAINTEXT) std::unique_ptr helper_; +#elif defined(USE_API_NOISE) + std::unique_ptr helper_; +#elif defined(USE_API_PLAINTEXT) + std::unique_ptr helper_; +#endif APIServer *parent_; // Group 2: Iterator union (saves ~16 bytes vs separate iterators) From 4928e678d1f54ee261789ab283280f317b425357 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Wed, 4 Mar 2026 13:37:22 -0600 Subject: [PATCH 40/42] [mixer][resampler][speaker] Use core static task manager (#14454) --- .../mixer/speaker/mixer_speaker.cpp | 91 +++------------ .../components/mixer/speaker/mixer_speaker.h | 18 +-- .../resampler/speaker/resampler_speaker.cpp | 60 +--------- .../resampler/speaker/resampler_speaker.h | 19 +-- .../speaker/media_player/audio_pipeline.cpp | 110 ++++-------------- .../speaker/media_player/audio_pipeline.h | 13 +-- 6 files changed, 49 insertions(+), 262 deletions(-) diff --git a/esphome/components/mixer/speaker/mixer_speaker.cpp b/esphome/components/mixer/speaker/mixer_speaker.cpp index 100acbebc33..8e1278206f4 100644 --- a/esphome/components/mixer/speaker/mixer_speaker.cpp +++ b/esphome/components/mixer/speaker/mixer_speaker.cpp @@ -438,24 +438,14 @@ void MixerSpeaker::loop() { // Handle pending start request if (event_group_bits & MIXER_TASK_COMMAND_START) { // Only start the task if it's fully stopped and cleaned up - if (!this->status_has_error() && (this->task_handle_ == nullptr) && (this->task_stack_buffer_ == nullptr)) { - esp_err_t err = this->start_task_(); - switch (err) { - case ESP_OK: - xEventGroupClearBits(this->event_group_, MIXER_TASK_COMMAND_START); - break; - case ESP_ERR_NO_MEM: - ESP_LOGE(TAG, "Failed to start; retrying in 1 second"); - this->status_momentary_error("memory-failure", 1000); - return; - case ESP_ERR_INVALID_STATE: - ESP_LOGE(TAG, "Failed to start; retrying in 1 second"); - this->status_momentary_error("task-failure", 1000); - return; - default: - ESP_LOGE(TAG, "Failed to start; retrying in 1 second"); - this->status_momentary_error("failure", 1000); - return; + if (!this->status_has_error() && !this->task_.is_created()) { + if (this->task_.create(audio_mixer_task, "mixer", TASK_STACK_SIZE, (void *) this, MIXER_TASK_PRIORITY, + this->task_stack_in_psram_)) { + xEventGroupClearBits(this->event_group_, MIXER_TASK_COMMAND_START); + } else { + ESP_LOGE(TAG, "Failed to start; retrying in 1 second"); + this->status_momentary_error("failure", 1000); + return; } } } @@ -478,13 +468,12 @@ void MixerSpeaker::loop() { xEventGroupClearBits(this->event_group_, MIXER_TASK_STATE_STOPPING); } if (event_group_bits & MIXER_TASK_STATE_STOPPED) { - if (this->delete_task_() == ESP_OK) { - ESP_LOGD(TAG, "Stopped"); - xEventGroupClearBits(this->event_group_, MIXER_TASK_ALL_BITS); - } + this->task_.deallocate(); + ESP_LOGD(TAG, "Stopped"); + xEventGroupClearBits(this->event_group_, MIXER_TASK_ALL_BITS); } - if (this->task_handle_ != nullptr) { + if (this->task_.is_created()) { // If the mixer task is running, check if all source speakers are stopped bool all_stopped = true; @@ -497,7 +486,7 @@ void MixerSpeaker::loop() { // Send stop command signal to the mixer task since no source speakers are active xEventGroupSetBits(this->event_group_, MIXER_TASK_COMMAND_STOP); } - } else if (this->task_stack_buffer_ == nullptr) { + } else { // Task is fully stopped and cleaned up, check if we can disable loop event_group_bits = xEventGroupGetBits(this->event_group_); if (event_group_bits == 0) { @@ -538,60 +527,6 @@ esp_err_t MixerSpeaker::start(audio::AudioStreamInfo &stream_info) { return ESP_OK; } -esp_err_t MixerSpeaker::start_task_() { - if (this->task_stack_buffer_ == nullptr) { - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE); - } - } - - if (this->task_stack_buffer_ == nullptr) { - return ESP_ERR_NO_MEM; - } - - if (this->task_handle_ == nullptr) { - this->task_handle_ = xTaskCreateStatic(audio_mixer_task, "mixer", TASK_STACK_SIZE, (void *) this, - MIXER_TASK_PRIORITY, this->task_stack_buffer_, &this->task_stack_); - } - - if (this->task_handle_ == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return ESP_OK; -} - -esp_err_t MixerSpeaker::delete_task_() { - if (this->task_handle_ != nullptr) { - // Delete the task - vTaskDelete(this->task_handle_); - this->task_handle_ = nullptr; - } - - if ((this->task_handle_ == nullptr) && (this->task_stack_buffer_ != nullptr)) { - // Deallocate the task stack buffer - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE); - } - - this->task_stack_buffer_ = nullptr; - } - - if ((this->task_handle_ != nullptr) || (this->task_stack_buffer_ != nullptr)) { - return ESP_ERR_INVALID_STATE; - } - - return ESP_OK; -} - void MixerSpeaker::copy_frames(const int16_t *input_buffer, audio::AudioStreamInfo input_stream_info, int16_t *output_buffer, audio::AudioStreamInfo output_stream_info, uint32_t frames_to_transfer) { diff --git a/esphome/components/mixer/speaker/mixer_speaker.h b/esphome/components/mixer/speaker/mixer_speaker.h index e920f9895a0..0e0b33c39bc 100644 --- a/esphome/components/mixer/speaker/mixer_speaker.h +++ b/esphome/components/mixer/speaker/mixer_speaker.h @@ -8,8 +8,8 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" +#include "esphome/core/static_task.h" -#include #include #include @@ -143,8 +143,6 @@ class MixerSpeaker : public Component { /// @param stream_info The calling source speaker's audio stream information /// @return ESP_ERR_NOT_SUPPORTED if the incoming stream is incompatible due to unsupported bits per sample /// ESP_ERR_INVALID_ARG if the incoming stream is incompatible to be mixed with the other input audio stream - /// ESP_ERR_NO_MEM if there isn't enough memory for the task's stack - /// ESP_ERR_INVALID_STATE if the task fails to start /// ESP_OK if the incoming stream is compatible and the mixer task starts esp_err_t start(audio::AudioStreamInfo &stream_info); @@ -188,16 +186,6 @@ class MixerSpeaker : public Component { static void audio_mixer_task(void *params); - /// @brief Starts the mixer task after allocating memory for the task stack. - /// @return ESP_ERR_NO_MEM if there isn't enough memory for the task's stack - /// ESP_ERR_INVALID_STATE if the task didn't start - /// ESP_OK if successful - esp_err_t start_task_(); - - /// @brief If the task is stopped, it sets the task handle to the nullptr and deallocates its stack - /// @return ESP_OK if the task was stopped, ESP_ERR_INVALID_STATE otherwise. - esp_err_t delete_task_(); - EventGroupHandle_t event_group_{nullptr}; FixedVector source_speakers_; @@ -207,9 +195,7 @@ class MixerSpeaker : public Component { bool queue_mode_; bool task_stack_in_psram_{false}; - TaskHandle_t task_handle_{nullptr}; - StaticTask_t task_stack_; - StackType_t *task_stack_buffer_{nullptr}; + StaticTask task_; optional audio_stream_info_; diff --git a/esphome/components/resampler/speaker/resampler_speaker.cpp b/esphome/components/resampler/speaker/resampler_speaker.cpp index 74420f906a1..1303bc459e5 100644 --- a/esphome/components/resampler/speaker/resampler_speaker.cpp +++ b/esphome/components/resampler/speaker/resampler_speaker.cpp @@ -147,7 +147,7 @@ void ResamplerSpeaker::loop() { xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::STATE_STOPPING); } if (event_group_bits & ResamplingEventGroupBits::STATE_STOPPED) { - this->delete_task_(); + this->task_.deallocate(); ESP_LOGD(TAG, "Stopped"); xEventGroupClearBits(this->event_group_, ResamplingEventGroupBits::ALL_BITS); } @@ -190,7 +190,7 @@ void ResamplerSpeaker::loop() { this->output_speaker_->stop(); } - if (this->output_speaker_->is_stopped() && (this->task_handle_ == nullptr)) { + if (this->output_speaker_->is_stopped() && !this->task_.is_created()) { // Only transition to stopped state once the output speaker and resampler task are fully stopped this->waiting_for_output_ = false; this->state_ = speaker::STATE_STOPPED; @@ -209,9 +209,6 @@ void ResamplerSpeaker::loop() { void ResamplerSpeaker::set_start_error_(esp_err_t err) { switch (err) { - case ESP_ERR_INVALID_STATE: - this->status_set_error(LOG_STR("Task failed to start")); - break; case ESP_ERR_NO_MEM: this->status_set_error(LOG_STR("Not enough memory")); break; @@ -267,36 +264,12 @@ esp_err_t ResamplerSpeaker::start_() { if (this->requires_resampling_()) { // Start the resampler task to handle converting sample rates - return this->start_task_(); - } - - return ESP_OK; -} - -esp_err_t ResamplerSpeaker::start_task_() { - if (this->task_stack_buffer_ == nullptr) { - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - this->task_stack_buffer_ = stack_allocator.allocate(TASK_STACK_SIZE); + if (!this->task_.create(resample_task, "resampler", TASK_STACK_SIZE, (void *) this, RESAMPLER_TASK_PRIORITY, + this->task_stack_in_psram_)) { + return ESP_ERR_NO_MEM; } } - if (this->task_stack_buffer_ == nullptr) { - return ESP_ERR_NO_MEM; - } - - if (this->task_handle_ == nullptr) { - this->task_handle_ = xTaskCreateStatic(resample_task, "resampler", TASK_STACK_SIZE, (void *) this, - RESAMPLER_TASK_PRIORITY, this->task_stack_buffer_, &this->task_stack_); - } - - if (this->task_handle_ == nullptr) { - return ESP_ERR_INVALID_STATE; - } - return ESP_OK; } @@ -305,33 +278,12 @@ void ResamplerSpeaker::stop() { this->send_command_(ResamplingEventGroupBits::CO void ResamplerSpeaker::enter_stopping_state_() { this->state_ = speaker::STATE_STOPPING; this->state_start_ms_ = App.get_loop_component_start_time(); - if (this->task_handle_ != nullptr) { + if (this->task_.is_created()) { xEventGroupSetBits(this->event_group_, ResamplingEventGroupBits::TASK_COMMAND_STOP); } this->output_speaker_->stop(); } -void ResamplerSpeaker::delete_task_() { - if (this->task_handle_ != nullptr) { - // Delete the suspended task - vTaskDelete(this->task_handle_); - this->task_handle_ = nullptr; - } - - if (this->task_stack_buffer_ != nullptr) { - // Deallocate the task stack buffer - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - stack_allocator.deallocate(this->task_stack_buffer_, TASK_STACK_SIZE); - } - - this->task_stack_buffer_ = nullptr; - } -} - void ResamplerSpeaker::finish() { this->send_command_(ResamplingEventGroupBits::COMMAND_FINISH); } bool ResamplerSpeaker::has_buffered_data() const { diff --git a/esphome/components/resampler/speaker/resampler_speaker.h b/esphome/components/resampler/speaker/resampler_speaker.h index c1ebd7e7b5b..cdbc1c22db4 100644 --- a/esphome/components/resampler/speaker/resampler_speaker.h +++ b/esphome/components/resampler/speaker/resampler_speaker.h @@ -7,8 +7,8 @@ #include "esphome/components/speaker/speaker.h" #include "esphome/core/component.h" +#include "esphome/core/static_task.h" -#include #include namespace esphome { @@ -57,15 +57,9 @@ class ResamplerSpeaker : public Component, public speaker::Speaker { protected: /// @brief Starts the output speaker after setting the resampled stream info. If resampling is required, it starts the /// task. - /// @return ESP_OK if resampling is required - /// return value of start_task_() if resampling is required - esp_err_t start_(); - - /// @brief Starts the resampler task after allocating the task stack /// @return ESP_OK if successful, - /// ESP_ERR_NO_MEM if the task stack couldn't be allocated - /// ESP_ERR_INVALID_STATE if the task wasn't created - esp_err_t start_task_(); + /// ESP_ERR_NO_MEM if the resampler task couldn't be created + esp_err_t start_(); /// @brief Transitions to STATE_STOPPING, records the stopping timestamp, sends the task stop command if the task is /// running, and stops the output speaker. @@ -74,9 +68,6 @@ class ResamplerSpeaker : public Component, public speaker::Speaker { /// @brief Sets the appropriate status error based on the start failure reason. void set_start_error_(esp_err_t err); - /// @brief Deletes the resampler task if suspended, deallocates the task stack, and resets the related pointers. - void delete_task_(); - /// @brief Sends a command via event group bits, enables the loop, and optionally wakes the main loop. void send_command_(uint32_t command_bit, bool wake_loop = false); @@ -92,9 +83,7 @@ class ResamplerSpeaker : public Component, public speaker::Speaker { bool task_stack_in_psram_{false}; bool waiting_for_output_{false}; - TaskHandle_t task_handle_{nullptr}; - StaticTask_t task_stack_; - StackType_t *task_stack_buffer_{nullptr}; + StaticTask task_; audio::AudioStreamInfo target_stream_info_; diff --git a/esphome/components/speaker/media_player/audio_pipeline.cpp b/esphome/components/speaker/media_player/audio_pipeline.cpp index 177743feb1d..8cea3abcfc9 100644 --- a/esphome/components/speaker/media_player/audio_pipeline.cpp +++ b/esphome/components/speaker/media_player/audio_pipeline.cpp @@ -87,20 +87,20 @@ void AudioPipeline::set_pause_state(bool pause_state) { } void AudioPipeline::suspend_tasks() { - if (this->read_task_handle_ != nullptr) { - vTaskSuspend(this->read_task_handle_); + if (this->read_task_.is_created()) { + vTaskSuspend(this->read_task_.get_handle()); } - if (this->decode_task_handle_ != nullptr) { - vTaskSuspend(this->decode_task_handle_); + if (this->decode_task_.is_created()) { + vTaskSuspend(this->decode_task_.get_handle()); } } void AudioPipeline::resume_tasks() { - if (this->read_task_handle_ != nullptr) { - vTaskResume(this->read_task_handle_); + if (this->read_task_.is_created()) { + vTaskResume(this->read_task_.get_handle()); } - if (this->decode_task_handle_ != nullptr) { - vTaskResume(this->decode_task_handle_); + if (this->decode_task_.is_created()) { + vTaskResume(this->decode_task_.get_handle()); } } @@ -159,7 +159,7 @@ AudioPipelineState AudioPipeline::process_state() { // Init command pending if (!(event_bits & EventGroupBits::PIPELINE_COMMAND_STOP)) { // Only start if there is no pending stop command - if ((this->read_task_handle_ == nullptr) || (this->decode_task_handle_ == nullptr)) { + if (!this->read_task_.is_created() || !this->decode_task_.is_created()) { // At least one task isn't running this->start_tasks_(); } @@ -202,8 +202,9 @@ AudioPipelineState AudioPipeline::process_state() { if (!this->is_playing_) { // The tasks have been stopped for two ``process_state`` calls in a row, so delete the tasks - if ((this->read_task_handle_ != nullptr) || (this->decode_task_handle_ != nullptr)) { - this->delete_tasks_(); + if (this->read_task_.is_created() || this->decode_task_.is_created()) { + this->read_task_.deallocate(); + this->decode_task_.deallocate(); if (this->hard_stop_) { // Stop command was sent, so immediately end the playback this->speaker_->stop(); @@ -234,7 +235,7 @@ AudioPipelineState AudioPipeline::process_state() { } } - if ((this->read_task_handle_ == nullptr) && (this->decode_task_handle_ == nullptr)) { + if (!this->read_task_.is_created() && !this->decode_task_.is_created()) { // No tasks are running, so the pipeline is stopped. xEventGroupClearBits(this->event_group_, EventGroupBits::PIPELINE_COMMAND_STOP); return AudioPipelineState::STOPPED; @@ -262,94 +263,25 @@ esp_err_t AudioPipeline::allocate_communications_() { } esp_err_t AudioPipeline::start_tasks_() { - if (this->read_task_handle_ == nullptr) { - if (this->read_task_stack_buffer_ == nullptr) { - // Reader task uses the AudioReader class which uses esp_http_client. This crashes on IDF 5.4 if the task stack is - // in PSRAM. As a workaround, always allocate the read task in internal memory. - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - this->read_task_stack_buffer_ = stack_allocator.allocate(READ_TASK_STACK_SIZE); - } - - if (this->read_task_stack_buffer_ == nullptr) { + if (!this->read_task_.is_created()) { + // Reader task uses the AudioReader class which uses esp_http_client. This crashes on IDF 5.4 if the task stack is + // in PSRAM. As a workaround, always allocate the read task in internal memory. + if (!this->read_task_.create(read_task, (this->base_name_ + "_read").c_str(), READ_TASK_STACK_SIZE, (void *) this, + this->priority_, false)) { return ESP_ERR_NO_MEM; } - - if (this->read_task_handle_ == nullptr) { - this->read_task_handle_ = - xTaskCreateStatic(read_task, (this->base_name_ + "_read").c_str(), READ_TASK_STACK_SIZE, (void *) this, - this->priority_, this->read_task_stack_buffer_, &this->read_task_stack_); - } - - if (this->read_task_handle_ == nullptr) { - return ESP_ERR_INVALID_STATE; - } } - if (this->decode_task_handle_ == nullptr) { - if (this->decode_task_stack_buffer_ == nullptr) { - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - this->decode_task_stack_buffer_ = stack_allocator.allocate(DECODE_TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - this->decode_task_stack_buffer_ = stack_allocator.allocate(DECODE_TASK_STACK_SIZE); - } - } - - if (this->decode_task_stack_buffer_ == nullptr) { + if (!this->decode_task_.is_created()) { + if (!this->decode_task_.create(decode_task, (this->base_name_ + "_decode").c_str(), DECODE_TASK_STACK_SIZE, + (void *) this, this->priority_, this->task_stack_in_psram_)) { return ESP_ERR_NO_MEM; } - - if (this->decode_task_handle_ == nullptr) { - this->decode_task_handle_ = - xTaskCreateStatic(decode_task, (this->base_name_ + "_decode").c_str(), DECODE_TASK_STACK_SIZE, (void *) this, - this->priority_, this->decode_task_stack_buffer_, &this->decode_task_stack_); - } - - if (this->decode_task_handle_ == nullptr) { - return ESP_ERR_INVALID_STATE; - } } return ESP_OK; } -void AudioPipeline::delete_tasks_() { - if (this->read_task_handle_ != nullptr) { - vTaskDelete(this->read_task_handle_); - - if (this->read_task_stack_buffer_ != nullptr) { - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - stack_allocator.deallocate(this->read_task_stack_buffer_, READ_TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - stack_allocator.deallocate(this->read_task_stack_buffer_, READ_TASK_STACK_SIZE); - } - - this->read_task_stack_buffer_ = nullptr; - this->read_task_handle_ = nullptr; - } - } - - if (this->decode_task_handle_ != nullptr) { - vTaskDelete(this->decode_task_handle_); - - if (this->decode_task_stack_buffer_ != nullptr) { - if (this->task_stack_in_psram_) { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_EXTERNAL); - stack_allocator.deallocate(this->decode_task_stack_buffer_, DECODE_TASK_STACK_SIZE); - } else { - RAMAllocator stack_allocator(RAMAllocator::ALLOC_INTERNAL); - stack_allocator.deallocate(this->decode_task_stack_buffer_, DECODE_TASK_STACK_SIZE); - } - - this->decode_task_stack_buffer_ = nullptr; - this->decode_task_handle_ = nullptr; - } - } -} - void AudioPipeline::read_task(void *params) { AudioPipeline *this_pipeline = (AudioPipeline *) params; diff --git a/esphome/components/speaker/media_player/audio_pipeline.h b/esphome/components/speaker/media_player/audio_pipeline.h index 6fffde6c206..2c785728359 100644 --- a/esphome/components/speaker/media_player/audio_pipeline.h +++ b/esphome/components/speaker/media_player/audio_pipeline.h @@ -8,10 +8,10 @@ #include "esphome/components/speaker/speaker.h" #include "esphome/core/ring_buffer.h" +#include "esphome/core/static_task.h" #include "esp_err.h" -#include #include #include @@ -104,9 +104,6 @@ class AudioPipeline { /// @return ESP_OK if successful or an appropriate error if not esp_err_t start_tasks_(); - /// @brief Resets the task related pointers and deallocates their stacks. - void delete_tasks_(); - std::string base_name_; UBaseType_t priority_; @@ -143,15 +140,11 @@ class AudioPipeline { // Handles reading the media file from flash or a url static void read_task(void *params); - TaskHandle_t read_task_handle_{nullptr}; - StaticTask_t read_task_stack_; - StackType_t *read_task_stack_buffer_{nullptr}; + StaticTask read_task_; // Decodes the media file into PCM audio static void decode_task(void *params); - TaskHandle_t decode_task_handle_{nullptr}; - StaticTask_t decode_task_stack_; - StackType_t *decode_task_stack_buffer_{nullptr}; + StaticTask decode_task_; }; } // namespace speaker From 9cb5d287a4c649ea424c4d133f839b655f38f877 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 09:49:31 -1000 Subject: [PATCH 41/42] [ota] Devirtualize OTA backend calls Each platform defines exactly one OTA backend subclass (marked final), so using concrete types in unique_ptr eliminates virtual dispatch overhead. - Move make_ota_backend() declaration from base header to each concrete backend header with concrete return type - Add ota_backend_factory.h convenience header for consumers - Use concrete unique_ptr types in ota_esphome, http_request, and web_server consumers --- esphome/components/esphome/ota/ota_esphome.h | 14 ++++++++++++-- .../http_request/ota/ota_http_request.cpp | 6 +----- .../http_request/ota/ota_http_request.h | 4 ++-- esphome/components/ota/ota_backend.h | 2 -- .../ota/ota_backend_arduino_libretiny.cpp | 2 +- .../ota/ota_backend_arduino_libretiny.h | 2 ++ .../components/ota/ota_backend_arduino_rp2040.cpp | 2 +- .../components/ota/ota_backend_arduino_rp2040.h | 2 ++ esphome/components/ota/ota_backend_esp8266.cpp | 2 +- esphome/components/ota/ota_backend_esp8266.h | 2 ++ esphome/components/ota/ota_backend_esp_idf.cpp | 2 +- esphome/components/ota/ota_backend_esp_idf.h | 2 ++ esphome/components/ota/ota_backend_factory.h | 15 +++++++++++++++ esphome/components/ota/ota_backend_host.cpp | 2 +- esphome/components/ota/ota_backend_host.h | 2 ++ .../components/web_server/ota/ota_web_server.cpp | 4 ++-- 16 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 esphome/components/ota/ota_backend_factory.h diff --git a/esphome/components/esphome/ota/ota_esphome.h b/esphome/components/esphome/ota/ota_esphome.h index 08edacad92f..7a2a8cdf614 100644 --- a/esphome/components/esphome/ota/ota_esphome.h +++ b/esphome/components/esphome/ota/ota_esphome.h @@ -2,7 +2,7 @@ #include "esphome/core/defines.h" #ifdef USE_OTA -#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/ota/ota_backend_factory.h" #include "esphome/components/socket/socket.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" @@ -86,7 +86,17 @@ class ESPHomeOTAComponent final : public ota::OTAComponent { socket::ListenSocket *server_{nullptr}; std::unique_ptr client_; - std::unique_ptr backend_; +#ifdef USE_ESP8266 + std::unique_ptr backend_; +#elif defined(USE_ESP32) + std::unique_ptr backend_; +#elif defined(USE_RP2040) + std::unique_ptr backend_; +#elif defined(USE_LIBRETINY) + std::unique_ptr backend_; +#elif defined(USE_HOST) + std::unique_ptr backend_; +#endif uint32_t client_connect_time_{0}; uint16_t port_; diff --git a/esphome/components/http_request/ota/ota_http_request.cpp b/esphome/components/http_request/ota/ota_http_request.cpp index 0db3a50b47d..9d40140b5a3 100644 --- a/esphome/components/http_request/ota/ota_http_request.cpp +++ b/esphome/components/http_request/ota/ota_http_request.cpp @@ -8,10 +8,6 @@ #include "esphome/components/md5/md5.h" #include "esphome/components/watchdog/watchdog.h" -#include "esphome/components/ota/ota_backend.h" -#include "esphome/components/ota/ota_backend_esp8266.h" -#include "esphome/components/ota/ota_backend_arduino_rp2040.h" -#include "esphome/components/ota/ota_backend_esp_idf.h" namespace esphome { namespace http_request { @@ -69,7 +65,7 @@ void OtaHttpRequestComponent::flash() { } } -void OtaHttpRequestComponent::cleanup_(std::unique_ptr backend, +void OtaHttpRequestComponent::cleanup_(decltype(ota::make_ota_backend()) backend, const std::shared_ptr &container) { if (this->update_started_) { ESP_LOGV(TAG, "Aborting OTA backend"); diff --git a/esphome/components/http_request/ota/ota_http_request.h b/esphome/components/http_request/ota/ota_http_request.h index 6d39b0d466c..36b8208a47a 100644 --- a/esphome/components/http_request/ota/ota_http_request.h +++ b/esphome/components/http_request/ota/ota_http_request.h @@ -1,6 +1,6 @@ #pragma once -#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/ota/ota_backend_factory.h" #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/helpers.h" @@ -39,7 +39,7 @@ class OtaHttpRequestComponent final : public ota::OTAComponent, public Parented< void flash(); protected: - void cleanup_(std::unique_ptr backend, const std::shared_ptr &container); + void cleanup_(decltype(ota::make_ota_backend()) backend, const std::shared_ptr &container); uint8_t do_ota_(); std::string get_url_with_auth_(const std::string &url); bool http_get_md5_(); diff --git a/esphome/components/ota/ota_backend.h b/esphome/components/ota/ota_backend.h index e03afd4fc6f..68e84160251 100644 --- a/esphome/components/ota/ota_backend.h +++ b/esphome/components/ota/ota_backend.h @@ -130,7 +130,5 @@ OTAGlobalCallback *get_global_ota_callback(); // - notify_state_deferred_() when in separate task (e.g., web_server OTA) // This ensures proper listener execution in all contexts. #endif -std::unique_ptr make_ota_backend(); - } // namespace ota } // namespace esphome diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.cpp b/esphome/components/ota/ota_backend_arduino_libretiny.cpp index b4ecad1227e..d364f750074 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.cpp +++ b/esphome/components/ota/ota_backend_arduino_libretiny.cpp @@ -12,7 +12,7 @@ namespace ota { static const char *const TAG = "ota.arduino_libretiny"; -std::unique_ptr make_ota_backend() { return make_unique(); } +std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoLibreTinyOTABackend::begin(size_t image_size) { // Handle UPDATE_SIZE_UNKNOWN (0) which is used by web server OTA diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.h b/esphome/components/ota/ota_backend_arduino_libretiny.h index 8f9d268eec6..60283455349 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.h +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -20,6 +20,8 @@ class ArduinoLibreTinyOTABackend final : public OTABackend { bool md5_set_{false}; }; +std::unique_ptr make_ota_backend(); + } // namespace ota } // namespace esphome diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.cpp b/esphome/components/ota/ota_backend_arduino_rp2040.cpp index ee1ba48d504..e2a57ec665b 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.cpp +++ b/esphome/components/ota/ota_backend_arduino_rp2040.cpp @@ -14,7 +14,7 @@ namespace ota { static const char *const TAG = "ota.arduino_rp2040"; -std::unique_ptr make_ota_backend() { return make_unique(); } +std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) { // OTA size of 0 is not currently handled, but diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.h b/esphome/components/ota/ota_backend_arduino_rp2040.h index 6a708f9c574..897afcac5b2 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.h +++ b/esphome/components/ota/ota_backend_arduino_rp2040.h @@ -22,6 +22,8 @@ class ArduinoRP2040OTABackend final : public OTABackend { bool md5_set_{false}; }; +std::unique_ptr make_ota_backend(); + } // namespace ota } // namespace esphome diff --git a/esphome/components/ota/ota_backend_esp8266.cpp b/esphome/components/ota/ota_backend_esp8266.cpp index 4b84708cd91..1f9a77e4261 100644 --- a/esphome/components/ota/ota_backend_esp8266.cpp +++ b/esphome/components/ota/ota_backend_esp8266.cpp @@ -48,7 +48,7 @@ namespace esphome::ota { static const char *const TAG = "ota.esp8266"; -std::unique_ptr make_ota_backend() { return make_unique(); } +std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes ESP8266OTABackend::begin(size_t image_size) { // Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space diff --git a/esphome/components/ota/ota_backend_esp8266.h b/esphome/components/ota/ota_backend_esp8266.h index 52f657f0065..cc6a8e0667e 100644 --- a/esphome/components/ota/ota_backend_esp8266.h +++ b/esphome/components/ota/ota_backend_esp8266.h @@ -54,5 +54,7 @@ class ESP8266OTABackend final : public OTABackend { bool md5_set_{false}; }; +std::unique_ptr make_ota_backend(); + } // namespace esphome::ota #endif // USE_ESP8266 diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp index 93c65a9624e..925bb396454 100644 --- a/esphome/components/ota/ota_backend_esp_idf.cpp +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -11,7 +11,7 @@ namespace esphome { namespace ota { -std::unique_ptr make_ota_backend() { return make_unique(); } +std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes IDFOTABackend::begin(size_t image_size) { #ifdef USE_OTA_ROLLBACK diff --git a/esphome/components/ota/ota_backend_esp_idf.h b/esphome/components/ota/ota_backend_esp_idf.h index 7f7f6115c50..7ca2d797ded 100644 --- a/esphome/components/ota/ota_backend_esp_idf.h +++ b/esphome/components/ota/ota_backend_esp_idf.h @@ -27,6 +27,8 @@ class IDFOTABackend final : public OTABackend { bool md5_set_{false}; }; +std::unique_ptr make_ota_backend(); + } // namespace ota } // namespace esphome #endif // USE_ESP32 diff --git a/esphome/components/ota/ota_backend_factory.h b/esphome/components/ota/ota_backend_factory.h new file mode 100644 index 00000000000..8d417977d2d --- /dev/null +++ b/esphome/components/ota/ota_backend_factory.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ota_backend.h" + +#ifdef USE_ESP8266 +#include "ota_backend_esp8266.h" +#elif defined(USE_ESP32) +#include "ota_backend_esp_idf.h" +#elif defined(USE_RP2040) +#include "ota_backend_arduino_rp2040.h" +#elif defined(USE_LIBRETINY) +#include "ota_backend_arduino_libretiny.h" +#elif defined(USE_HOST) +#include "ota_backend_host.h" +#endif diff --git a/esphome/components/ota/ota_backend_host.cpp b/esphome/components/ota/ota_backend_host.cpp index ddab174bed7..2e2132418d8 100644 --- a/esphome/components/ota/ota_backend_host.cpp +++ b/esphome/components/ota/ota_backend_host.cpp @@ -8,7 +8,7 @@ namespace esphome::ota { // Stub implementation - OTA is not supported on host platform. // All methods return error codes to allow compilation of configs with OTA triggers. -std::unique_ptr make_ota_backend() { return make_unique(); } +std::unique_ptr make_ota_backend() { return make_unique(); } OTAResponseTypes HostOTABackend::begin(size_t image_size) { return OTA_RESPONSE_ERROR_UPDATE_PREPARE; } diff --git a/esphome/components/ota/ota_backend_host.h b/esphome/components/ota/ota_backend_host.h index 5a2dcfcf39b..0d190cd3c81 100644 --- a/esphome/components/ota/ota_backend_host.h +++ b/esphome/components/ota/ota_backend_host.h @@ -17,5 +17,7 @@ class HostOTABackend final : public OTABackend { bool supports_compression() override { return false; } }; +std::unique_ptr make_ota_backend(); + } // namespace esphome::ota #endif diff --git a/esphome/components/web_server/ota/ota_web_server.cpp b/esphome/components/web_server/ota/ota_web_server.cpp index 4be162ccd32..c52b1a1fda4 100644 --- a/esphome/components/web_server/ota/ota_web_server.cpp +++ b/esphome/components/web_server/ota/ota_web_server.cpp @@ -1,7 +1,7 @@ #include "ota_web_server.h" #ifdef USE_WEBSERVER_OTA -#include "esphome/components/ota/ota_backend.h" +#include "esphome/components/ota/ota_backend_factory.h" #include "esphome/core/application.h" #include "esphome/core/log.h" @@ -71,7 +71,7 @@ class OTARequestHandler : public AsyncWebHandler { bool ota_success_{false}; private: - std::unique_ptr ota_backend_{nullptr}; + decltype(ota::make_ota_backend()) ota_backend_{nullptr}; }; void OTARequestHandler::report_ota_progress_(AsyncWebServerRequest *request) { From acef15b9822cc994b7e454252ab35f2cb300e2aa Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Mar 2026 09:56:15 -1000 Subject: [PATCH 42/42] [ota] Devirtualize OTA backend calls Each platform defines exactly one OTA backend subclass (marked final), so using concrete types in unique_ptr eliminates virtual dispatch overhead. - Remove OTABackend base class - no longer needed since all consumers use concrete types directly - Move make_ota_backend() declaration to each concrete backend header with concrete return type - Add ota_backend_factory.h convenience header for consumers - Use concrete unique_ptr types in ota_esphome, http_request, and web_server consumers --- esphome/components/ota/ota_backend.h | 11 ----------- .../components/ota/ota_backend_arduino_libretiny.h | 14 +++++++------- .../components/ota/ota_backend_arduino_rp2040.h | 14 +++++++------- esphome/components/ota/ota_backend_esp8266.h | 14 +++++++------- esphome/components/ota/ota_backend_esp_idf.h | 14 +++++++------- esphome/components/ota/ota_backend_factory.h | 2 ++ esphome/components/ota/ota_backend_host.h | 14 +++++++------- 7 files changed, 37 insertions(+), 46 deletions(-) diff --git a/esphome/components/ota/ota_backend.h b/esphome/components/ota/ota_backend.h index 68e84160251..bc603a6e9e2 100644 --- a/esphome/components/ota/ota_backend.h +++ b/esphome/components/ota/ota_backend.h @@ -49,17 +49,6 @@ enum OTAState { OTA_ERROR, }; -class OTABackend { - public: - virtual ~OTABackend() = default; - virtual OTAResponseTypes begin(size_t image_size) = 0; - virtual void set_update_md5(const char *md5) = 0; - virtual OTAResponseTypes write(uint8_t *data, size_t len) = 0; - virtual OTAResponseTypes end() = 0; - virtual void abort() = 0; - virtual bool supports_compression() = 0; -}; - /** Listener interface for OTA state changes. * * Components can implement this interface to receive OTA state updates diff --git a/esphome/components/ota/ota_backend_arduino_libretiny.h b/esphome/components/ota/ota_backend_arduino_libretiny.h index 60283455349..4514bf84bda 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.h +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -7,14 +7,14 @@ namespace esphome { namespace ota { -class ArduinoLibreTinyOTABackend final : public OTABackend { +class ArduinoLibreTinyOTABackend final { public: - OTAResponseTypes begin(size_t image_size) override; - void set_update_md5(const char *md5) override; - OTAResponseTypes write(uint8_t *data, size_t len) override; - OTAResponseTypes end() override; - void abort() override; - bool supports_compression() override { return false; } + OTAResponseTypes begin(size_t image_size); + void set_update_md5(const char *md5); + OTAResponseTypes write(uint8_t *data, size_t len); + OTAResponseTypes end(); + void abort(); + bool supports_compression() { return false; } private: bool md5_set_{false}; diff --git a/esphome/components/ota/ota_backend_arduino_rp2040.h b/esphome/components/ota/ota_backend_arduino_rp2040.h index 897afcac5b2..0956cb4b4b9 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.h +++ b/esphome/components/ota/ota_backend_arduino_rp2040.h @@ -9,14 +9,14 @@ namespace esphome { namespace ota { -class ArduinoRP2040OTABackend final : public OTABackend { +class ArduinoRP2040OTABackend final { public: - OTAResponseTypes begin(size_t image_size) override; - void set_update_md5(const char *md5) override; - OTAResponseTypes write(uint8_t *data, size_t len) override; - OTAResponseTypes end() override; - void abort() override; - bool supports_compression() override { return false; } + OTAResponseTypes begin(size_t image_size); + void set_update_md5(const char *md5); + OTAResponseTypes write(uint8_t *data, size_t len); + OTAResponseTypes end(); + void abort(); + bool supports_compression() { return false; } private: bool md5_set_{false}; diff --git a/esphome/components/ota/ota_backend_esp8266.h b/esphome/components/ota/ota_backend_esp8266.h index cc6a8e0667e..6213289accb 100644 --- a/esphome/components/ota/ota_backend_esp8266.h +++ b/esphome/components/ota/ota_backend_esp8266.h @@ -12,15 +12,15 @@ namespace esphome::ota { /// OTA backend for ESP8266 using native SDK functions. /// This implementation bypasses the Arduino Updater library to save ~228 bytes of RAM /// by not having a global Update object in .bss. -class ESP8266OTABackend final : public OTABackend { +class ESP8266OTABackend final { public: - OTAResponseTypes begin(size_t image_size) override; - void set_update_md5(const char *md5) override; - OTAResponseTypes write(uint8_t *data, size_t len) override; - OTAResponseTypes end() override; - void abort() override; + OTAResponseTypes begin(size_t image_size); + void set_update_md5(const char *md5); + OTAResponseTypes write(uint8_t *data, size_t len); + OTAResponseTypes end(); + void abort(); // Compression supported in all ESP8266 Arduino versions ESPHome supports (>= 2.7.0) - bool supports_compression() override { return true; } + bool supports_compression() { return true; } protected: /// Erase flash sector if current address is at sector boundary diff --git a/esphome/components/ota/ota_backend_esp_idf.h b/esphome/components/ota/ota_backend_esp_idf.h index 7ca2d797ded..a0f538afc02 100644 --- a/esphome/components/ota/ota_backend_esp_idf.h +++ b/esphome/components/ota/ota_backend_esp_idf.h @@ -10,14 +10,14 @@ namespace esphome { namespace ota { -class IDFOTABackend final : public OTABackend { +class IDFOTABackend final { public: - OTAResponseTypes begin(size_t image_size) override; - void set_update_md5(const char *md5) override; - OTAResponseTypes write(uint8_t *data, size_t len) override; - OTAResponseTypes end() override; - void abort() override; - bool supports_compression() override { return false; } + OTAResponseTypes begin(size_t image_size); + void set_update_md5(const char *md5); + OTAResponseTypes write(uint8_t *data, size_t len); + OTAResponseTypes end(); + void abort(); + bool supports_compression() { return false; } private: esp_ota_handle_t update_handle_{0}; diff --git a/esphome/components/ota/ota_backend_factory.h b/esphome/components/ota/ota_backend_factory.h index 8d417977d2d..b6456e64fc2 100644 --- a/esphome/components/ota/ota_backend_factory.h +++ b/esphome/components/ota/ota_backend_factory.h @@ -13,3 +13,5 @@ #elif defined(USE_HOST) #include "ota_backend_host.h" #endif + +namespace esphome::ota {} // namespace esphome::ota diff --git a/esphome/components/ota/ota_backend_host.h b/esphome/components/ota/ota_backend_host.h index 0d190cd3c81..300facf72f9 100644 --- a/esphome/components/ota/ota_backend_host.h +++ b/esphome/components/ota/ota_backend_host.h @@ -7,14 +7,14 @@ namespace esphome::ota { /// Stub OTA backend for host platform - allows compilation but does not implement OTA. /// All operations return error codes immediately. This enables configurations with /// OTA triggers to compile for host platform during development. -class HostOTABackend final : public OTABackend { +class HostOTABackend final { public: - OTAResponseTypes begin(size_t image_size) override; - void set_update_md5(const char *md5) override; - OTAResponseTypes write(uint8_t *data, size_t len) override; - OTAResponseTypes end() override; - void abort() override; - bool supports_compression() override { return false; } + OTAResponseTypes begin(size_t image_size); + void set_update_md5(const char *md5); + OTAResponseTypes write(uint8_t *data, size_t len); + OTAResponseTypes end(); + void abort(); + bool supports_compression() { return false; } }; std::unique_ptr make_ota_backend();