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/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index f00ef4ee048..3cbc8c2eac6 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 @@ -274,7 +275,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 +336,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,61 +344,19 @@ 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 - } +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 - - // 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); + 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, - uint8_t message_type, APIConnection *conn, - uint32_t remaining_size) { + 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(); @@ -405,7 +364,7 @@ uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResp // 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 + // 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); @@ -425,16 +384,17 @@ 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); + 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, - uint8_t message_type, APIConnection *conn, + 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, message_type, conn, remaining_size); + return fill_and_encode_entity_info(entity, msg, size_fn, encode_fn, conn, remaining_size); } #ifdef USE_BINARY_SENSOR @@ -448,16 +408,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 +431,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 +441,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 +473,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 +484,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 +527,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 +552,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 +597,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 +607,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 +620,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 +651,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 +696,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 +723,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 +761,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 +772,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 +792,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 +817,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 +844,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 +868,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 +878,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 +897,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 +917,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 +934,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 +943,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 +971,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 +980,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 +1006,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 +1023,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 +1064,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 +1090,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 +1245,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 +1277,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 +1312,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 +1321,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 +1368,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 +1379,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 +1415,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 +1439,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 +1447,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 +1471,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 +1502,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 +1559,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 +1688,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 +1788,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 +1799,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 +1838,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 +1867,73 @@ 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) { +#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)); + } +#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(); 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); } +// 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) { +#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(); + + // 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 + + 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) { const bool is_log_message = (message_type == SubscribeLogsResponse::MESSAGE_TYPE); @@ -2291,17 +2292,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 +2321,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..54b6db68000 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" @@ -123,7 +129,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 +153,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 +263,19 @@ 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 &); + // Function pointer type for type-erased size calculation + using CalculateSizeFn = uint32_t (*)(const void *); + + template bool send_message(const T &msg) { + 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, &proto_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 +330,68 @@ 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); - - // 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) { - 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); + // 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(); } - // 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); + // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) + static void encode_msg_noop(const void *, ProtoWriteBuffer &) {} - // Wrapper for entity types that have a device_class field + // 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) { + 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(), &proto_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, &proto_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, + 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, &proto_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, uint8_t message_type, - 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, &calc_size, + &proto_encode_msg, conn, remaining_size); + } #ifdef USE_VOICE_ASSISTANT // Helper to check voice assistant validity and connection ownership @@ -466,7 +524,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) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 3f23943b12f..2dcdb2b8dbf 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 { - 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()); +uint32_t HelloResponse::calculate_size() const { + uint32_t size = 0; + 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 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 { - size.add_uint32(1, this->area_id); - size.add_length(1, this->name.size()); +uint32_t AreaInfo::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, this->area_id); + size += ProtoSize::calc_length(1, this->name.size()); + return 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 { - size.add_uint32(1, this->device_id); - size.add_length(1, this->name.size()); - size.add_uint32(1, this->area_id); +uint32_t DeviceInfo::calculate_size() const { + uint32_t size = 0; + 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 void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { @@ -120,60 +126,62 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(24, this->zwave_home_id); #endif } -void DeviceInfoResponse::calculate_size(ProtoSize &size) const { - 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 DeviceInfoResponse::calculate_size() const { + uint32_t size = 0; + 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.add_bool(1, this->has_deep_sleep); + size += ProtoSize::calc_bool(1, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME - size.add_length(1, this->project_name.size()); + size += ProtoSize::calc_length(1, this->project_name.size()); #endif #ifdef ESPHOME_PROJECT_NAME - size.add_length(1, this->project_version.size()); + size += ProtoSize::calc_length(1, this->project_version.size()); #endif #ifdef USE_WEBSERVER - size.add_uint32(1, this->webserver_port); + size += ProtoSize::calc_uint32(1, this->webserver_port); #endif #ifdef USE_BLUETOOTH_PROXY - size.add_uint32(1, this->bluetooth_proxy_feature_flags); + size += ProtoSize::calc_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::calc_length(1, this->manufacturer.size()); + size += ProtoSize::calc_length(1, this->friendly_name.size()); #ifdef USE_VOICE_ASSISTANT - size.add_uint32(2, this->voice_assistant_feature_flags); + size += ProtoSize::calc_uint32(2, this->voice_assistant_feature_flags); #endif #ifdef USE_AREAS - size.add_length(2, this->suggested_area.size()); + size += ProtoSize::calc_length(2, this->suggested_area.size()); #endif #ifdef USE_BLUETOOTH_PROXY - size.add_length(2, this->bluetooth_mac_address.size()); + size += ProtoSize::calc_length(2, this->bluetooth_mac_address.size()); #endif #ifdef USE_API_NOISE - size.add_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.add_message_object_force(2, it); + size += ProtoSize::calc_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::calc_message_force(2, it.calculate_size()); } #endif #ifdef USE_AREAS - size.add_message_object(2, this->area); + size += ProtoSize::calc_message(2, this->area.calculate_size()); #endif #ifdef USE_ZWAVE_PROXY - size.add_uint32(2, this->zwave_proxy_feature_flags); + size += ProtoSize::calc_uint32(2, this->zwave_proxy_feature_flags); #endif #ifdef USE_ZWAVE_PROXY - size.add_uint32(2, this->zwave_home_id); + size += ProtoSize::calc_uint32(2, this->zwave_home_id); #endif + return size; } #ifdef USE_BINARY_SENSOR void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { @@ -191,20 +199,22 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesBinarySensorResponse::calculate_size(ProtoSize &size) const { - 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 ListEntitiesBinarySensorResponse::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->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.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return 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 { - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } #endif #ifdef USE_COVER @@ -242,23 +254,25 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(13, this->device_id); #endif } -void ListEntitiesCoverResponse::calculate_size(ProtoSize &size) const { - 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 ListEntitiesCoverResponse::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_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.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); - size.add_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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -269,14 +283,16 @@ void CoverStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void CoverStateResponse::calculate_size(ProtoSize &size) const { - 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 CoverStateResponse::calculate_size() const { + uint32_t size = 0; + 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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool CoverCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -337,27 +353,29 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(13, this->device_id); #endif } -void ListEntitiesFanResponse::calculate_size(ProtoSize &size) const { - 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 ListEntitiesFanResponse::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_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.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_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.add_length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -370,16 +388,18 @@ void FanStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void FanStateResponse::calculate_size(ProtoSize &size) const { - 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 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_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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -464,30 +484,32 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(16, this->device_id); #endif } -void ListEntitiesLightResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesLightResponse::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()); if (!this->supported_color_modes->empty()) { for (const auto &it : *this->supported_color_modes) { - size.add_uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } - size.add_float(1, this->min_mireds); - size.add_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.add_length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } - size.add_bool(1, this->disabled_by_default); + size += ProtoSize::calc_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif + return size; } void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -507,23 +529,25 @@ void LightStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void LightStateResponse::calculate_size(ProtoSize &size) const { - 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 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_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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -653,23 +677,25 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void ListEntitiesSensorResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesSensorResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return 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 { - size.add_fixed32(1, this->key); - size.add_float(1, this->state); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } #endif #ifdef USE_SWITCH @@ -704,20 +732,22 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesSwitchResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesSwitchResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return 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 { - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); +uint32_t SwitchStateResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool(1, this->state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool SwitchCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -774,19 +806,21 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesTextSensorResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesTextSensorResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return 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 { - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return 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 { - size.add_uint32(1, static_cast(this->level)); - size.add_length(1, this->message_len_); +uint32_t SubscribeLogsResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, static_cast(this->level)); + size += ProtoSize::calc_length(1, this->message_len_); + return 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 { + uint32_t size = 0; + size += ProtoSize::calc_bool(1, this->success); + return 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 { - size.add_length(1, this->key.size()); - size.add_length(1, this->value.size()); +uint32_t HomeassistantServiceMap::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_length(1, this->key.size()); + size += ProtoSize::calc_length(1, this->value.size()); + return size; } void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->service); @@ -873,21 +917,35 @@ void HomeassistantActionRequest::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(8, this->response_template); #endif } -void HomeassistantActionRequest::calculate_size(ProtoSize &size) const { - 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 HomeassistantActionRequest::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_length(1, this->service.size()); + if (!this->data.empty()) { + for (const auto &it : this->data) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); + } + } + if (!this->data_template.empty()) { + for (const auto &it : this->data_template) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); + } + } + if (!this->variables.empty()) { + for (const auto &it : this->variables) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); + } + } + size += ProtoSize::calc_bool(1, this->is_event); #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES - size.add_uint32(1, this->call_id); + size += ProtoSize::calc_uint32(1, this->call_id); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size.add_bool(1, this->wants_response); + size += ProtoSize::calc_bool(1, this->wants_response); #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON - size.add_length(1, this->response_template.size()); + size += ProtoSize::calc_length(1, this->response_template.size()); #endif + return size; } #endif #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES @@ -929,10 +987,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 { - size.add_length(1, this->entity_id.size()); - size.add_length(1, this->attribute.size()); - size.add_bool(1, this->once); +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); + return size; } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -1030,9 +1090,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 { - size.add_length(1, this->name.size()); - size.add_uint32(1, static_cast(this->type)); +uint32_t ListEntitiesServicesArgument::calculate_size() const { + uint32_t size = 0; + 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 { buffer.encode_string(1, this->name); @@ -1042,11 +1104,17 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(4, static_cast(this->supports_response)); } -void ListEntitiesServicesResponse::calculate_size(ProtoSize &size) const { - 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)); +uint32_t ListEntitiesServicesResponse::calculate_size() const { + uint32_t size = 0; + 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::calc_message_force(1, it.calculate_size()); + } + } + size += ProtoSize::calc_uint32(1, static_cast(this->supports_response)); + return size; } bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1161,13 +1229,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 { - size.add_uint32(1, this->call_id); - size.add_bool(1, this->success); - size.add_length(1, this->error_message.size()); +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_length(1, this->error_message.size()); #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON - size.add_length(1, this->response_data_len); + size += ProtoSize::calc_length(1, this->response_data_len); #endif + return size; } #endif #ifdef USE_CAMERA @@ -1184,18 +1254,20 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesCameraResponse::calculate_size(ProtoSize &size) const { - 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 ListEntitiesCameraResponse::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_bool(1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_uint32(1, static_cast(this->entity_category)); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1205,13 +1277,15 @@ void CameraImageResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void CameraImageResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_length(1, this->data_len_); - size.add_bool(1, this->done); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool CameraImageRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1271,60 +1345,62 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(27, this->feature_flags); } -void ListEntitiesClimateResponse::calculate_size(ProtoSize &size) const { - 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 ListEntitiesClimateResponse::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_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.add_uint32_force(1, static_cast(it)); + size += ProtoSize::calc_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::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.add_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.add_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.add_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.add_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.add_length_force(2, strlen(it)); + size += ProtoSize::calc_length_force(2, strlen(it)); } } - size.add_bool(2, this->disabled_by_default); + size += ProtoSize::calc_bool(2, this->disabled_by_default); #ifdef USE_ENTITY_ICON - size.add_length(2, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif - size.add_uint32(2, this->feature_flags); + size += ProtoSize::calc_uint32(2, this->feature_flags); + return size; } void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1345,24 +1421,26 @@ void ClimateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(16, this->device_id); #endif } -void ClimateStateResponse::calculate_size(ProtoSize &size) const { - 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 ClimateStateResponse::calculate_size() const { + uint32_t size = 0; + 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.add_uint32(2, this->device_id); + size += ProtoSize::calc_uint32(2, this->device_id); #endif + return size; } bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1477,27 +1555,29 @@ void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer &buffer) const { } buffer.encode_uint32(12, this->supported_features); } -void ListEntitiesWaterHeaterResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesWaterHeaterResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::calc_bool(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_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::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.add_uint32_force(1, static_cast(it)); + size += ProtoSize::calc_uint32_force(1, static_cast(it)); } } - size.add_uint32(1, this->supported_features); + size += ProtoSize::calc_uint32(1, this->supported_features); + return size; } void WaterHeaterStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1511,17 +1591,19 @@ 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 { - 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 WaterHeaterStateResponse::calculate_size() const { + uint32_t size = 0; + 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.add_uint32(1, this->device_id); + size += ProtoSize::calc_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); + 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) { switch (field_id) { @@ -1584,24 +1666,26 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(14, this->device_id); #endif } -void ListEntitiesNumberResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesNumberResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1611,13 +1695,15 @@ void NumberStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void NumberStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_float(1, this->state); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool NumberCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1662,23 +1748,25 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesSelectResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesSelectResponse::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()); #ifdef USE_ENTITY_ICON - size.add_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.add_length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } - size.add_bool(1, this->disabled_by_default); - size.add_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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1688,13 +1776,15 @@ void SelectStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void SelectStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool SelectCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1749,25 +1839,27 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(11, this->device_id); #endif } -void ListEntitiesSirenResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesSirenResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_length(1, this->icon.size()); #endif - size.add_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.add_length_force(1, strlen(it)); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1776,12 +1868,14 @@ void SirenStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void SirenStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_bool(1, this->state); +uint32_t SirenStateResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_bool(1, this->state); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool SirenCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1856,22 +1950,24 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesLockResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesLockResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -1880,12 +1976,14 @@ void LockStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void LockStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->state)); +uint32_t LockStateResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1942,19 +2040,21 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesButtonResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesButtonResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool ButtonCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -1987,12 +2087,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 { - 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); +uint32_t MediaPlayerSupportedFormat::calculate_size() const { + uint32_t size = 0; + 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 { buffer.encode_string(1, this->object_id); @@ -2012,21 +2114,27 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(11, this->feature_flags); } -void ListEntitiesMediaPlayerResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesMediaPlayerResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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::calc_message_force(1, it.calculate_size()); + } + } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size.add_uint32(1, this->feature_flags); + size += ProtoSize::calc_uint32(1, this->feature_flags); + return size; } void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2037,14 +2145,16 @@ void MediaPlayerStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(5, this->device_id); #endif } -void MediaPlayerStateResponse::calculate_size(ProtoSize &size) const { - 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 MediaPlayerStateResponse::calculate_size() const { + uint32_t size = 0; + 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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2118,21 +2228,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 { - 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); +uint32_t BluetoothLERawAdvertisement::calculate_size() const { + uint32_t size = 0; + 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 { 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 { + 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::calc_message_force(1, this->advertisements[i].calculate_size()); } + return size; } bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2159,11 +2273,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 { - size.add_uint64(1, this->address); - size.add_bool(1, this->connected); - size.add_uint32(1, this->mtu); - size.add_int32(1, this->error); +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_uint32(1, this->mtu); + size += ProtoSize::calc_int32(1, this->error); + return size; } bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2183,13 +2299,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 { + 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::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_uint64_force(1, this->uuid[1]); } - size.add_uint32(1, this->handle); - size.add_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 { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2203,15 +2321,21 @@ 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 { + 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::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_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); + 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::calc_message_force(1, it.calculate_size()); + } + } + size += ProtoSize::calc_uint32(1, this->short_uuid); + return size; } void BluetoothGATTService::encode(ProtoWriteBuffer &buffer) const { if (this->uuid[0] != 0 || this->uuid[1] != 0) { @@ -2224,14 +2348,20 @@ 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 { + 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::calc_uint64_force(1, this->uuid[0]); + size += ProtoSize::calc_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); + size += ProtoSize::calc_uint32(1, this->handle); + if (!this->characteristics.empty()) { + for (const auto &it : this->characteristics) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); + } + } + size += ProtoSize::calc_uint32(1, this->short_uuid); + return size; } void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint64(1, this->address); @@ -2239,14 +2369,24 @@ void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_message(2, it); } } -void BluetoothGATTGetServicesResponse::calculate_size(ProtoSize &size) const { - size.add_uint64(1, this->address); - size.add_repeated_message(1, this->services); +uint32_t BluetoothGATTGetServicesResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint64(1, this->address); + if (!this->services.empty()) { + for (const auto &it : this->services) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); + } + } + return 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 { + uint32_t size = 0; + size += ProtoSize::calc_uint64(1, this->address); + return size; +} bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: @@ -2265,10 +2405,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 { - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_length(1, this->data_len_); +uint32_t BluetoothGATTReadResponse::calculate_size() const { + uint32_t size = 0; + 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) { switch (field_id) { @@ -2357,10 +2499,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 { - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_length(1, this->data_len_); +uint32_t BluetoothGATTNotifyDataResponse::calculate_size() const { + uint32_t size = 0; + 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 { buffer.encode_uint32(1, this->free); @@ -2371,80 +2515,96 @@ void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer &buffer) const { } } } -void BluetoothConnectionsFreeResponse::calculate_size(ProtoSize &size) const { - size.add_uint32(1, this->free); - size.add_uint32(1, this->limit); +uint32_t BluetoothConnectionsFreeResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, this->free); + size += ProtoSize::calc_uint32(1, this->limit); for (const auto &it : this->allocated) { if (it != 0) { - size.add_uint64_force(1, it); + size += ProtoSize::calc_uint64_force(1, it); } } + return 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 { - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); - size.add_int32(1, this->error); +uint32_t BluetoothGATTErrorResponse::calculate_size() const { + uint32_t size = 0; + 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 { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); } -void BluetoothGATTWriteResponse::calculate_size(ProtoSize &size) const { - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); +uint32_t BluetoothGATTWriteResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); + return 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 { - size.add_uint64(1, this->address); - size.add_uint32(1, this->handle); +uint32_t BluetoothGATTNotifyResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint64(1, this->address); + size += ProtoSize::calc_uint32(1, this->handle); + return 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 { - size.add_uint64(1, this->address); - size.add_bool(1, this->paired); - size.add_int32(1, this->error); +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_int32(1, this->error); + return 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 { - size.add_uint64(1, this->address); - size.add_bool(1, this->success); - size.add_int32(1, this->error); +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_int32(1, this->error); + return 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 { - size.add_uint64(1, this->address); - size.add_bool(1, this->success); - size.add_int32(1, this->error); +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_int32(1, this->error); + return 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 { - 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)); +uint32_t BluetoothScannerStateResponse::calculate_size() const { + uint32_t size = 0; + 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) { switch (field_id) { @@ -2476,10 +2636,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 { - size.add_uint32(1, this->noise_suppression_level); - size.add_uint32(1, this->auto_gain); - size.add_float(1, this->volume_multiplier); +uint32_t VoiceAssistantAudioSettings::calculate_size() const { + uint32_t size = 0; + 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 { buffer.encode_bool(1, this->start); @@ -2488,12 +2650,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 { - 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()); +uint32_t VoiceAssistantRequest::calculate_size() const { + uint32_t size = 0; + 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) { switch (field_id) { @@ -2570,9 +2734,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 { - size.add_length(1, this->data_len); - size.add_bool(1, this->end); +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); + return size; } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2638,7 +2804,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 { + uint32_t size = 0; + size += ProtoSize::calc_bool(1, this->success); + return size; +} void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(1, this->id); buffer.encode_string(2, this->wake_word); @@ -2646,14 +2816,16 @@ void VoiceAssistantWakeWord::encode(ProtoWriteBuffer &buffer) const { buffer.encode_string(3, it, true); } } -void VoiceAssistantWakeWord::calculate_size(ProtoSize &size) const { - size.add_length(1, this->id.size()); - size.add_length(1, this->wake_word.size()); +uint32_t VoiceAssistantWakeWord::calculate_size() const { + uint32_t size = 0; + 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.add_length_force(1, it.size()); + size += ProtoSize::calc_length_force(1, it.size()); } } + return size; } bool VoiceAssistantExternalWakeWord::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2715,14 +2887,20 @@ void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer &buffer) const } buffer.encode_uint32(3, this->max_active_wake_words); } -void VoiceAssistantConfigurationResponse::calculate_size(ProtoSize &size) const { - 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 VoiceAssistantConfigurationResponse::calculate_size() const { + uint32_t size = 0; + if (!this->available_wake_words.empty()) { + for (const auto &it : this->available_wake_words) { + size += ProtoSize::calc_message_force(1, it.calculate_size()); } } - size.add_uint32(1, this->max_active_wake_words); + if (!this->active_wake_words->empty()) { + for (const auto &it : *this->active_wake_words) { + size += ProtoSize::calc_length_force(1, it.size()); + } + } + size += ProtoSize::calc_uint32(1, this->max_active_wake_words); + return size; } bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -2752,21 +2930,23 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer &buffer) con buffer.encode_uint32(11, this->device_id); #endif } -void ListEntitiesAlarmControlPanelResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesAlarmControlPanelResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2775,12 +2955,14 @@ void AlarmControlPanelStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void AlarmControlPanelStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_uint32(1, static_cast(this->state)); +uint32_t AlarmControlPanelStateResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_uint32(1, static_cast(this->state)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2837,22 +3019,24 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesTextResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesTextResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2862,13 +3046,15 @@ void TextStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void TextStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_length(1, this->state.size()); - size.add_bool(1, this->missing_state); +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); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool TextCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2918,18 +3104,20 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesDateResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesDateResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::calc_bool(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -2941,15 +3129,17 @@ void DateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void DateStateResponse::calculate_size(ProtoSize &size) const { - 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 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_uint32(1, this->year); + size += ProtoSize::calc_uint32(1, this->month); + size += ProtoSize::calc_uint32(1, this->day); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool DateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2997,18 +3187,20 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesTimeResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesTimeResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::calc_bool(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3020,15 +3212,17 @@ void TimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(6, this->device_id); #endif } -void TimeStateResponse::calculate_size(ProtoSize &size) const { - 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 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_uint32(1, this->hour); + size += ProtoSize::calc_uint32(1, this->minute); + size += ProtoSize::calc_uint32(1, this->second); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool TimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3080,24 +3274,26 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(10, this->device_id); #endif } -void ListEntitiesEventResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesEventResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_length_force(1, strlen(it)); + size += ProtoSize::calc_length_force(1, strlen(it)); } } #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void EventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3106,12 +3302,14 @@ void EventResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(3, this->device_id); #endif } -void EventResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_length(1, this->event_type.size()); +uint32_t EventResponse::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_fixed32(1, this->key); + size += ProtoSize::calc_length(1, this->event_type.size()); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } #endif #ifdef USE_VALVE @@ -3132,22 +3330,24 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(12, this->device_id); #endif } -void ListEntitiesValveResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesValveResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3157,13 +3357,15 @@ void ValveStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void ValveStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_float(1, this->position); - size.add_uint32(1, static_cast(this->current_operation)); +uint32_t ValveStateResponse::calculate_size() const { + uint32_t size = 0; + 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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool ValveCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3211,18 +3413,20 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(8, this->device_id); #endif } -void ListEntitiesDateTimeResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesDateTimeResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::calc_bool(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3232,13 +3436,15 @@ void DateTimeStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(4, this->device_id); #endif } -void DateTimeStateResponse::calculate_size(ProtoSize &size) const { - size.add_fixed32(1, this->key); - size.add_bool(1, this->missing_state); - size.add_fixed32(1, this->epoch_seconds); +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_fixed32(1, this->epoch_seconds); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool DateTimeCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3281,19 +3487,21 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(9, this->device_id); #endif } -void ListEntitiesUpdateResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesUpdateResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_fixed32(1, this->key); @@ -3310,20 +3518,22 @@ void UpdateStateResponse::encode(ProtoWriteBuffer &buffer) const { buffer.encode_uint32(11, this->device_id); #endif } -void UpdateStateResponse::calculate_size(ProtoSize &size) const { - 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 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_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.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif + return size; } bool UpdateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -3365,7 +3575,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 { + uint32_t size = 0; + size += ProtoSize::calc_length(1, this->data_len); + return size; +} bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: @@ -3392,9 +3606,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 { - size.add_uint32(1, static_cast(this->type)); - size.add_length(1, this->data_len); +uint32_t ZWaveProxyRequest::calculate_size() const { + uint32_t size = 0; + size += ProtoSize::calc_uint32(1, static_cast(this->type)); + size += ProtoSize::calc_length(1, this->data_len); + return size; } #endif #ifdef USE_INFRARED @@ -3412,19 +3628,21 @@ void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer &buffer) const { #endif buffer.encode_uint32(8, this->capabilities); } -void ListEntitiesInfraredResponse::calculate_size(ProtoSize &size) const { - size.add_length(1, this->object_id.size()); - size.add_fixed32(1, this->key); - size.add_length(1, this->name.size()); +uint32_t ListEntitiesInfraredResponse::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()); #ifdef USE_ENTITY_ICON - size.add_length(1, this->icon.size()); + size += ProtoSize::calc_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::calc_bool(1, this->disabled_by_default); + size += ProtoSize::calc_uint32(1, static_cast(this->entity_category)); #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size.add_uint32(1, this->capabilities); + size += ProtoSize::calc_uint32(1, this->capabilities); + return size; } #endif #ifdef USE_IR_RF @@ -3478,16 +3696,18 @@ 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 { + uint32_t size = 0; #ifdef USE_DEVICES - size.add_uint32(1, this->device_id); + size += ProtoSize::calc_uint32(1, this->device_id); #endif - size.add_fixed32(1, this->key); + size += ProtoSize::calc_fixed32(1, this->key); if (!this->timings->empty()) { for (const auto &it : *this->timings) { - size.add_sint32_force(1, it); + size += ProtoSize::calc_sint32_force(1, it); } } + return size; } #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 769335610ad..64e1d5d1545 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -388,8 +388,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -453,8 +453,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -468,8 +468,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -533,8 +533,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -564,8 +564,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -581,8 +581,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -603,8 +603,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -621,8 +621,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -663,8 +663,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -683,8 +683,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -730,8 +730,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -757,8 +757,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -821,8 +821,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -838,8 +838,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -857,8 +857,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -873,8 +873,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -907,8 +907,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -924,8 +924,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -963,8 +963,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -996,8 +996,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1010,8 +1010,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1039,8 +1039,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1083,8 +1083,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1173,8 +1173,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1192,8 +1192,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1262,8 +1262,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1279,8 +1279,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1301,8 +1301,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1352,8 +1352,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1380,8 +1380,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1438,8 +1438,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1459,8 +1459,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1503,8 +1503,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1520,8 +1520,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1554,8 +1554,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1571,8 +1571,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1608,8 +1608,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1624,8 +1624,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1669,8 +1669,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1685,8 +1685,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1722,8 +1722,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1754,8 +1754,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1772,8 +1772,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1790,8 +1790,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1846,8 +1846,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1863,8 +1863,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1900,8 +1900,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1928,8 +1928,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1943,8 +1943,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1957,8 +1957,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1974,8 +1974,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -1990,8 +1990,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2029,8 +2029,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2124,8 +2124,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2142,8 +2142,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2160,8 +2160,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2177,8 +2177,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2194,8 +2194,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2212,8 +2212,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2230,8 +2230,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2248,8 +2248,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2266,8 +2266,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2312,8 +2312,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2332,8 +2332,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2394,8 +2394,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2452,8 +2452,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2465,8 +2465,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2515,8 +2515,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2550,8 +2550,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2566,8 +2566,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2605,8 +2605,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2622,8 +2622,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2656,8 +2656,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2675,8 +2675,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2710,8 +2710,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2729,8 +2729,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2766,8 +2766,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2782,8 +2782,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2803,8 +2803,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2820,8 +2820,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2855,8 +2855,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2872,8 +2872,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2906,8 +2906,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2930,8 +2930,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2965,8 +2965,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -2984,8 +2984,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -3004,8 +3004,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; + uint32_t calculate_size() const; #ifdef HAS_PROTO_MESSAGE_DUMP const char *dump_to(DumpBuffer &out) const override; #endif @@ -3051,8 +3051,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; + 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/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..06816fe3e05 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -359,11 +359,11 @@ 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_) - 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/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/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..702208d9de6 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -364,7 +364,11 @@ 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); + // 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: @@ -452,20 +456,20 @@ 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 {} + 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"; } #endif protected: - // Non-virtual: messages are never deleted polymorphically. - // Protected prevents accidental `delete base_ptr` (compile error). + // Non-virtual destructor is protected to prevent polymorphic deletion. ~ProtoMessage() = default; }; @@ -494,32 +498,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 * @@ -616,320 +595,77 @@ 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 calc_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 calc_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 calc_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 calc_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 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; } - - /** - * @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 calc_fixed32(uint32_t field_id_size, uint32_t value) { + return value ? field_id_size + 4 : 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 calc_sfixed32(uint32_t field_id_size, int32_t value) { + return value ? field_id_size + 4 : 0; } - - // 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 calc_sint32(uint32_t field_id_size, int32_t value) { + return value ? field_id_size + varint(encode_zigzag32(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 calc_sint32_force(uint32_t field_id_size, int32_t value) { + return field_id_size + varint(encode_zigzag32(value)); } - - // 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 calc_int64(uint32_t field_id_size, int64_t value) { + return value ? field_id_size + varint(value) : 0; } - - /** - * @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 calc_int64_force(uint32_t field_id_size, int64_t value) { + return field_id_size + varint(value); } - - /** - * @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 calc_uint64(uint32_t field_id_size, uint64_t value) { + return value ? field_id_size + varint(value) : 0; } - - /** - * @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 calc_uint64_force(uint32_t field_id_size, uint64_t value) { + return field_id_size + varint(value); } - - /** - * @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 calc_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 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 calc_length_force(uint32_t field_id_size, size_t len) { + return field_id_size + varint(static_cast(len)) + static_cast(len); } - - // 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); - } + static constexpr uint32_t calc_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 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); + static constexpr uint32_t calc_sint64_force(uint32_t field_id_size, int64_t value) { + return field_id_size + varint(encode_zigzag64(value)); } - - /** - * @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); - } + static constexpr uint32_t calc_fixed64(uint32_t field_id_size, uint64_t value) { + return value ? field_id_size + 8 : 0; } - - /** - * @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; + static constexpr uint32_t calc_sfixed64(uint32_t field_id_size, int64_t value) { + return value ? field_id_size + 8 : 0; } - - /** - * @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 - */ - inline void add_message_object(uint32_t field_id_size, const ProtoMessage &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); + 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; } - - /** - * @brief Calculates and adds the size of a nested message field to the total message size (force version) - * - * @param message The nested message object - */ - inline void add_message_object_force(uint32_t field_id_size, const ProtoMessage &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); - } - - /** - * @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 calc_message_force(uint32_t field_id_size, uint32_t nested_size) { + return field_id_size + varint(nested_size) + nested_size; } }; // Implementation of methods that depend on ProtoSize being fully defined -inline uint32_t ProtoMessage::calculated_size() const { - ProtoSize size; - this->calculate_size(size); - return size.get_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()) @@ -949,31 +685,30 @@ 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) { - // Calculate the message size first - ProtoSize msg_size; - value.calculate_size(msg_size); - uint32_t msg_length_bytes = msg_size.get_size(); +// 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); +} - // 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 +// 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) { + this->encode_message(field_id, value.calculate_size(), &value, &proto_encode_msg, 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) { 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 } @@ -993,14 +728,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..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) { @@ -333,7 +328,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 +414,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 +427,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 +440,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 +453,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 +463,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/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/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}; 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/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/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'; 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) { 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/ota/ota_backend.h b/esphome/components/ota/ota_backend.h index e03afd4fc6f..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 @@ -130,7 +119,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..4514bf84bda 100644 --- a/esphome/components/ota/ota_backend_arduino_libretiny.h +++ b/esphome/components/ota/ota_backend_arduino_libretiny.h @@ -7,19 +7,21 @@ 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}; }; +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..0956cb4b4b9 100644 --- a/esphome/components/ota/ota_backend_arduino_rp2040.h +++ b/esphome/components/ota/ota_backend_arduino_rp2040.h @@ -9,19 +9,21 @@ 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}; }; +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..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 @@ -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..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}; @@ -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..b6456e64fc2 --- /dev/null +++ b/esphome/components/ota/ota_backend_factory.h @@ -0,0 +1,17 @@ +#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 + +namespace esphome::ota {} // namespace esphome::ota 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..300facf72f9 100644 --- a/esphome/components/ota/ota_backend_host.h +++ b/esphome/components/ota/ota_backend_host.h @@ -7,15 +7,17 @@ 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(); + } // namespace esphome::ota #endif 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); 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) { 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/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/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 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); } 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/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) { diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index 62b35b9d60b..1c17aa8cb3a 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(); @@ -2119,15 +2120,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}; 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/esphome/config_validation.py b/esphome/config_validation.py index b5b5189c7c3..1eac53e9b20 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -398,17 +398,10 @@ 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 - -# 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/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.""" diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 498e9a11e07..556485d56ce 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -170,6 +170,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() { @@ -190,7 +198,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(); } diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index b7460dc033f..399798b2386 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -542,9 +542,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 diff --git a/esphome/core/config.py b/esphome/core/config.py index 4f526404fe8..3ae29b4df57 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -188,6 +188,14 @@ 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 + 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 38a92d98201..3be3282bc4a 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 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 @@ -180,9 +181,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" @@ -196,9 +197,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") diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 9c9cda4d36e..85352689e6b 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -270,18 +270,21 @@ 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 + 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.{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 +413,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::calc_fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -434,7 +437,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::calc_float({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -457,7 +460,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 +480,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 +500,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 +521,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::calc_fixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -542,7 +545,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::calc_fixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -563,7 +566,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 +650,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::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.add_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 @@ -721,7 +724,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 = "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: # For message types, we can't easily estimate the submessage size without @@ -822,7 +827,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::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 @@ -897,7 +902,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::calc_length({self.calculate_field_id_size()}, this->{self.field_name}_len);" class PointerToStringBufferType(PointerToBufferTypeBase): @@ -939,7 +944,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::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 @@ -1103,9 +1108,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::calc_length_force({field_id_size}, {length_field});" + # For non-repeated fields, length already checks for zero + return f"size += ProtoSize::calc_length({field_id_size}, {length_field});" def get_estimated_size(self) -> int: # Estimate based on typical BLE advertisement size @@ -1132,7 +1137,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 +1173,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 +1195,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::calc_sfixed32({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 4 @@ -1214,7 +1219,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::calc_sfixed64({field_id_size}, {name});" def get_fixed_size_bytes(self) -> int: return 8 @@ -1237,7 +1242,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 +1262,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 +1699,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::calc_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 +1724,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::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" @@ -2233,23 +2244,19 @@ 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 # 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 += " uint32_t size = 0;\n" + o += indent("\n".join(size_calc)) + "\n" + o += " return size;\n" + o += "}\n" cpp += o - prot = "void calculate_size(ProtoSize &size) const override;" + 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 @@ -2933,14 +2940,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" 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 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']}" + )