diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index fd08e87bbf..93e84702e2 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -732,7 +732,6 @@ message SubscribeLogsResponse { LogLevel level = 1; bytes message = 3; - bool send_failed = 4; } // ==================== NOISE ENCRYPTION ==================== @@ -1464,19 +1463,19 @@ message BluetoothGATTGetServicesRequest { } message BluetoothGATTDescriptor { - repeated uint64 uuid = 1; + repeated uint64 uuid = 1 [(fixed_array_size) = 2]; uint32 handle = 2; } message BluetoothGATTCharacteristic { - repeated uint64 uuid = 1; + repeated uint64 uuid = 1 [(fixed_array_size) = 2]; uint32 handle = 2; uint32 properties = 3; repeated BluetoothGATTDescriptor descriptors = 4; } message BluetoothGATTService { - repeated uint64 uuid = 1; + repeated uint64 uuid = 1 [(fixed_array_size) = 2]; uint32 handle = 2; repeated BluetoothGATTCharacteristic characteristics = 3; } @@ -1487,7 +1486,7 @@ message BluetoothGATTGetServicesResponse { option (ifdef) = "USE_BLUETOOTH_PROXY"; uint64 address = 1; - repeated BluetoothGATTService services = 2; + repeated BluetoothGATTService services = 2 [(fixed_array_size) = 1]; } message BluetoothGATTGetServicesDoneResponse { diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bc0afd49eb..60dc0a113d 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -225,24 +225,16 @@ void APIConnection::loop() { if (this->image_reader_ && this->image_reader_->available() && this->helper_->can_write_without_blocking()) { uint32_t to_send = std::min((size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available()); bool done = this->image_reader_->available() == to_send; - uint32_t msg_size = 0; - ProtoSize::add_fixed_field<4>(msg_size, 1, true); - // partial message size calculated manually since its a special case - // 1 for the data field, varint for the data size, and the data itself - msg_size += 1 + ProtoSize::varint(to_send) + to_send; - ProtoSize::add_bool_field(msg_size, 1, done); - auto buffer = this->create_buffer(msg_size); - // fixed32 key = 1; - buffer.encode_fixed32(1, camera::Camera::instance()->get_object_id_hash()); - // bytes data = 2; - buffer.encode_bytes(2, this->image_reader_->peek_data_buffer(), to_send); - // bool done = 3; - buffer.encode_bool(3, done); + CameraImageResponse msg; + msg.key = camera::Camera::instance()->get_object_id_hash(); + msg.set_data(this->image_reader_->peek_data_buffer(), to_send); + msg.done = done; +#ifdef USE_DEVICES + msg.device_id = camera::Camera::instance()->get_device_id(); +#endif - bool success = this->send_buffer(buffer, CameraImageResponse::MESSAGE_TYPE); - - if (success) { + if (this->send_message_(msg, CameraImageResponse::MESSAGE_TYPE)) { this->image_reader_->consume_data(to_send); if (done) { this->image_reader_->return_image(); @@ -256,8 +248,10 @@ void APIConnection::loop() { if (state_subs_at_ < static_cast(subs.size())) { auto &it = subs[state_subs_at_]; SubscribeHomeAssistantStateResponse resp; - resp.entity_id = it.entity_id; - resp.attribute = it.attribute.value(); + resp.set_entity_id(StringRef(it.entity_id)); + // attribute.value() returns temporary - must store it + std::string attribute_value = it.attribute.value(); + resp.set_attribute(StringRef(attribute_value)); resp.once = it.once; if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) { state_subs_at_++; @@ -268,14 +262,14 @@ void APIConnection::loop() { } } -DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) { +bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) { // remote initiated disconnect_client // don't close yet, we still need to send the disconnect response // close will happen on next loop ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str()); this->flags_.next_close = true; DisconnectResponse resp; - return resp; + return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE); } void APIConnection::on_disconnect_response(const DisconnectResponse &value) { this->helper_->close(); @@ -352,7 +346,7 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne bool is_single) { auto *binary_sensor = static_cast(entity); ListEntitiesBinarySensorResponse msg; - msg.device_class = binary_sensor->get_device_class(); + msg.set_device_class(binary_sensor->get_device_class_ref()); msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); return fill_and_encode_entity_info(binary_sensor, msg, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); @@ -384,7 +378,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(); - msg.device_class = cover->get_device_class(); + msg.set_device_class(cover->get_device_class_ref()); return fill_and_encode_entity_info(cover, msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -419,7 +413,7 @@ uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *co if (traits.supports_direction()) msg.direction = static_cast(fan->direction); if (traits.supports_preset_modes()) - msg.preset_mode = fan->preset_mode; + msg.set_preset_mode(StringRef(fan->preset_mode)); return fill_and_encode_entity_state(fan, msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } uint16_t APIConnection::try_send_fan_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, @@ -476,8 +470,11 @@ uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection * resp.color_temperature = values.get_color_temperature(); resp.cold_white = values.get_cold_white(); resp.warm_white = values.get_warm_white(); - if (light->supports_effects()) - resp.effect = light->get_effect_name(); + if (light->supports_effects()) { + // get_effect_name() returns temporary std::string - must store it + std::string effect_name = light->get_effect_name(); + resp.set_effect(StringRef(effect_name)); + } return fill_and_encode_entity_state(light, resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, @@ -553,10 +550,10 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection * bool is_single) { auto *sensor = static_cast(entity); ListEntitiesSensorResponse msg; - msg.unit_of_measurement = sensor->get_unit_of_measurement(); + msg.set_unit_of_measurement(sensor->get_unit_of_measurement_ref()); msg.accuracy_decimals = sensor->get_accuracy_decimals(); msg.force_update = sensor->get_force_update(); - msg.device_class = sensor->get_device_class(); + msg.set_device_class(sensor->get_device_class_ref()); msg.state_class = static_cast(sensor->get_state_class()); return fill_and_encode_entity_info(sensor, msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); @@ -583,7 +580,7 @@ uint16_t APIConnection::try_send_switch_info(EntityBase *entity, APIConnection * auto *a_switch = static_cast(entity); ListEntitiesSwitchResponse msg; msg.assumed_state = a_switch->assumed_state(); - msg.device_class = a_switch->get_device_class(); + msg.set_device_class(a_switch->get_device_class_ref()); return fill_and_encode_entity_info(a_switch, msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -608,7 +605,7 @@ uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnec bool is_single) { auto *text_sensor = static_cast(entity); TextSensorStateResponse resp; - resp.state = text_sensor->state; + resp.set_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, is_single); @@ -617,7 +614,7 @@ uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnect bool is_single) { auto *text_sensor = static_cast(entity); ListEntitiesTextSensorResponse msg; - msg.device_class = text_sensor->get_device_class(); + msg.set_device_class(text_sensor->get_device_class_ref()); return fill_and_encode_entity_info(text_sensor, msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -645,13 +642,19 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection } if (traits.get_supports_fan_modes() && climate->fan_mode.has_value()) resp.fan_mode = static_cast(climate->fan_mode.value()); - if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value()) - resp.custom_fan_mode = climate->custom_fan_mode.value(); + if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value()) { + // custom_fan_mode.value() returns temporary - must store it + std::string custom_fan_mode = climate->custom_fan_mode.value(); + resp.set_custom_fan_mode(StringRef(custom_fan_mode)); + } if (traits.get_supports_presets() && climate->preset.has_value()) { resp.preset = static_cast(climate->preset.value()); } - if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value()) - resp.custom_preset = climate->custom_preset.value(); + if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value()) { + // custom_preset.value() returns temporary - must store it + std::string custom_preset = climate->custom_preset.value(); + resp.set_custom_preset(StringRef(custom_preset)); + } if (traits.get_supports_swing_modes()) resp.swing_mode = static_cast(climate->swing_mode); if (traits.get_supports_current_humidity()) @@ -737,9 +740,9 @@ uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection * bool is_single) { auto *number = static_cast(entity); ListEntitiesNumberResponse msg; - msg.unit_of_measurement = number->traits.get_unit_of_measurement(); + msg.set_unit_of_measurement(number->traits.get_unit_of_measurement_ref()); msg.mode = static_cast(number->traits.get_mode()); - msg.device_class = number->traits.get_device_class(); + msg.set_device_class(number->traits.get_device_class_ref()); msg.min_value = number->traits.get_min_value(); msg.max_value = number->traits.get_max_value(); msg.step = number->traits.get_step(); @@ -852,7 +855,7 @@ uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *c bool is_single) { auto *text = static_cast(entity); TextStateResponse resp; - resp.state = text->state; + resp.set_state(StringRef(text->state)); resp.missing_state = !text->has_state(); return fill_and_encode_entity_state(text, resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -864,7 +867,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co msg.mode = static_cast(text->traits.get_mode()); msg.min_length = text->traits.get_min_length(); msg.max_length = text->traits.get_max_length(); - msg.pattern = text->traits.get_pattern(); + msg.set_pattern(text->traits.get_pattern_ref()); return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -885,7 +888,7 @@ uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection bool is_single) { auto *select = static_cast(entity); SelectStateResponse resp; - resp.state = select->state; + resp.set_state(StringRef(select->state)); resp.missing_state = !select->has_state(); return fill_and_encode_entity_state(select, resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -911,7 +914,7 @@ uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection * bool is_single) { auto *button = static_cast(entity); ListEntitiesButtonResponse msg; - msg.device_class = button->get_device_class(); + msg.set_device_class(button->get_device_class_ref()); return fill_and_encode_entity_info(button, msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -980,7 +983,7 @@ uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *c auto *valve = static_cast(entity); ListEntitiesValveResponse msg; auto traits = valve->get_traits(); - msg.device_class = valve->get_device_class(); + msg.set_device_class(valve->get_device_class_ref()); msg.assumed_state = traits.get_is_assumed_state(); msg.supports_position = traits.get_supports_position(); msg.supports_stop = traits.get_supports_stop(); @@ -1022,13 +1025,13 @@ uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnec auto traits = media_player->get_traits(); msg.supports_pause = traits.get_supports_pause(); for (auto &supported_format : traits.get_supported_formats()) { - MediaPlayerSupportedFormat media_format; - media_format.format = supported_format.format; + msg.supported_formats.emplace_back(); + auto &media_format = msg.supported_formats.back(); + media_format.set_format(StringRef(supported_format.format)); media_format.sample_rate = supported_format.sample_rate; media_format.num_channels = supported_format.num_channels; media_format.purpose = static_cast(supported_format.purpose); media_format.sample_bytes = supported_format.sample_bytes; - msg.supported_formats.push_back(media_format); } return fill_and_encode_entity_info(media_player, msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn, remaining_size, is_single); @@ -1091,6 +1094,12 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) { } #endif +bool APIConnection::send_get_time_response(const GetTimeRequest &msg) { + GetTimeResponse resp; + resp.epoch_seconds = ::time(nullptr); + return this->send_message(resp, GetTimeResponse::MESSAGE_TYPE); +} + #ifdef USE_BLUETOOTH_PROXY void APIConnection::subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) { bluetooth_proxy::global_bluetooth_proxy->subscribe_api_connection(this, msg.flags); @@ -1121,12 +1130,12 @@ void APIConnection::bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) bluetooth_proxy::global_bluetooth_proxy->bluetooth_gatt_notify(msg); } -BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_free( +bool APIConnection::send_subscribe_bluetooth_connections_free_response( const SubscribeBluetoothConnectionsFreeRequest &msg) { BluetoothConnectionsFreeResponse resp; resp.free = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_free(); resp.limit = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_limit(); - return resp; + return this->send_message(resp, BluetoothConnectionsFreeResponse::MESSAGE_TYPE); } void APIConnection::bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) { @@ -1187,28 +1196,27 @@ void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnno } } -VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configuration( - const VoiceAssistantConfigurationRequest &msg) { +bool APIConnection::send_voice_assistant_get_configuration_response(const VoiceAssistantConfigurationRequest &msg) { VoiceAssistantConfigurationResponse resp; if (!this->check_voice_assistant_api_connection_()) { - return resp; + return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE); } auto &config = voice_assistant::global_voice_assistant->get_configuration(); for (auto &wake_word : config.available_wake_words) { - VoiceAssistantWakeWord resp_wake_word; - resp_wake_word.id = wake_word.id; - resp_wake_word.wake_word = wake_word.wake_word; + resp.available_wake_words.emplace_back(); + auto &resp_wake_word = resp.available_wake_words.back(); + resp_wake_word.set_id(StringRef(wake_word.id)); + resp_wake_word.set_wake_word(StringRef(wake_word.wake_word)); for (const auto &lang : wake_word.trained_languages) { resp_wake_word.trained_languages.push_back(lang); } - resp.available_wake_words.push_back(std::move(resp_wake_word)); } for (auto &wake_word_id : config.active_wake_words) { resp.active_wake_words.push_back(wake_word_id); } resp.max_active_wake_words = config.max_active_wake_words; - return resp; + return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE); } void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) { @@ -1281,7 +1289,7 @@ void APIConnection::send_event(event::Event *event, const std::string &event_typ uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn, uint32_t remaining_size, bool is_single) { EventResponse resp; - resp.event_type = event_type; + resp.set_event_type(StringRef(event_type)); return fill_and_encode_entity_state(event, resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -1289,7 +1297,7 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c bool is_single) { auto *event = static_cast(entity); ListEntitiesEventResponse msg; - msg.device_class = event->get_device_class(); + msg.set_device_class(event->get_device_class_ref()); for (const auto &event_type : event->get_event_types()) msg.event_types.push_back(event_type); return fill_and_encode_entity_info(event, msg, ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size, @@ -1313,11 +1321,11 @@ uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection resp.has_progress = true; resp.progress = update->update_info.progress; } - resp.current_version = update->update_info.current_version; - resp.latest_version = update->update_info.latest_version; - resp.title = update->update_info.title; - resp.release_summary = update->update_info.summary; - resp.release_url = update->update_info.release_url; + resp.set_current_version(StringRef(update->update_info.current_version)); + resp.set_latest_version(StringRef(update->update_info.latest_version)); + resp.set_title(StringRef(update->update_info.title)); + resp.set_release_summary(StringRef(update->update_info.summary)); + resp.set_release_url(StringRef(update->update_info.release_url)); } return fill_and_encode_entity_state(update, resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -1325,7 +1333,7 @@ uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection * bool is_single) { auto *update = static_cast(entity); ListEntitiesUpdateResponse msg; - msg.device_class = update->get_device_class(); + msg.set_device_class(update->get_device_class_ref()); return fill_and_encode_entity_info(update, msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size, is_single); } @@ -1350,26 +1358,10 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) { #endif bool APIConnection::try_send_log_message(int level, const char *tag, const char *line, size_t message_len) { - // Pre-calculate message size to avoid reallocations - uint32_t msg_size = 0; - - // Add size for level field (field ID 1, varint type) - // 1 byte for field tag + size of the level varint - msg_size += 1 + api::ProtoSize::varint(static_cast(level)); - - // Add size for string field (field ID 3, string type) - // 1 byte for field tag + size of length varint + string length - msg_size += 1 + api::ProtoSize::varint(static_cast(message_len)) + message_len; - - // Create a pre-sized buffer - auto buffer = this->create_buffer(msg_size); - - // Encode the message (SubscribeLogsResponse) - buffer.encode_uint32(1, static_cast(level)); // LogLevel level = 1 - buffer.encode_string(3, line, message_len); // string message = 3 - - // SubscribeLogsResponse - 29 - return this->send_buffer(buffer, SubscribeLogsResponse::MESSAGE_TYPE); + SubscribeLogsResponse msg; + msg.level = static_cast(level); + msg.set_message(reinterpret_cast(line), message_len); + return this->send_message_(msg, SubscribeLogsResponse::MESSAGE_TYPE); } void APIConnection::complete_authentication_() { @@ -1390,7 +1382,7 @@ void APIConnection::complete_authentication_() { #endif } -HelloResponse APIConnection::hello(const HelloRequest &msg) { +bool APIConnection::send_hello_response(const HelloRequest &msg) { this->client_info_.name = msg.client_info; this->client_info_.peername = this->helper_->getpeername(); this->client_api_version_major_ = msg.api_version_major; @@ -1401,8 +1393,10 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { HelloResponse resp; resp.api_version_major = 1; resp.api_version_minor = 10; - resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; - resp.name = App.get_name(); + // Temporary string for concatenation - will be valid during send_message call + std::string server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")"; + resp.set_server_info(StringRef(server_info)); + resp.set_name(StringRef(App.get_name())); #ifdef USE_API_PASSWORD // Password required - wait for authentication @@ -1412,9 +1406,9 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { this->complete_authentication_(); #endif - return resp; + return this->send_message(resp, HelloResponse::MESSAGE_TYPE); } -ConnectResponse APIConnection::connect(const ConnectRequest &msg) { +bool APIConnection::send_connect_response(const ConnectRequest &msg) { bool correct = true; #ifdef USE_API_PASSWORD correct = this->parent_->check_password(msg.password); @@ -1426,48 +1420,71 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { if (correct) { this->complete_authentication_(); } - return resp; + return this->send_message(resp, ConnectResponse::MESSAGE_TYPE); } -DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { + +bool APIConnection::send_ping_response(const PingRequest &msg) { + PingResponse resp; + return this->send_message(resp, PingResponse::MESSAGE_TYPE); +} + +bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) { DeviceInfoResponse resp{}; #ifdef USE_API_PASSWORD resp.uses_password = true; #endif - resp.name = App.get_name(); - resp.friendly_name = App.get_friendly_name(); + resp.set_name(StringRef(App.get_name())); + resp.set_friendly_name(StringRef(App.get_friendly_name())); #ifdef USE_AREAS - resp.suggested_area = App.get_area(); + resp.set_suggested_area(StringRef(App.get_area())); #endif - resp.mac_address = get_mac_address_pretty(); - resp.esphome_version = ESPHOME_VERSION; - resp.compilation_time = App.get_compilation_time(); + // mac_address must store temporary string - will be valid during send_message call + std::string mac_address = get_mac_address_pretty(); + resp.set_mac_address(StringRef(mac_address)); + + // Compile-time StringRef constants + static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION); + resp.set_esphome_version(ESPHOME_VERSION_REF); + + // get_compilation_time() returns temporary std::string - must store it + std::string compilation_time = App.get_compilation_time(); + resp.set_compilation_time(StringRef(compilation_time)); + + // Compile-time StringRef constants for manufacturers #if defined(USE_ESP8266) || defined(USE_ESP32) - resp.manufacturer = "Espressif"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Espressif"); #elif defined(USE_RP2040) - resp.manufacturer = "Raspberry Pi"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Raspberry Pi"); #elif defined(USE_BK72XX) - resp.manufacturer = "Beken"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Beken"); #elif defined(USE_LN882X) - resp.manufacturer = "Lightning"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Lightning"); #elif defined(USE_RTL87XX) - resp.manufacturer = "Realtek"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Realtek"); #elif defined(USE_HOST) - resp.manufacturer = "Host"; + static constexpr auto MANUFACTURER = StringRef::from_lit("Host"); #endif - resp.model = ESPHOME_BOARD; + resp.set_manufacturer(MANUFACTURER); + + static constexpr auto MODEL = StringRef::from_lit(ESPHOME_BOARD); + resp.set_model(MODEL); #ifdef USE_DEEP_SLEEP resp.has_deep_sleep = deep_sleep::global_has_deep_sleep; #endif #ifdef ESPHOME_PROJECT_NAME - resp.project_name = ESPHOME_PROJECT_NAME; - resp.project_version = ESPHOME_PROJECT_VERSION; + static constexpr auto PROJECT_NAME = StringRef::from_lit(ESPHOME_PROJECT_NAME); + static constexpr auto PROJECT_VERSION = StringRef::from_lit(ESPHOME_PROJECT_VERSION); + resp.set_project_name(PROJECT_NAME); + resp.set_project_version(PROJECT_VERSION); #endif #ifdef USE_WEBSERVER resp.webserver_port = USE_WEBSERVER_PORT; #endif #ifdef USE_BLUETOOTH_PROXY resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags(); - resp.bluetooth_mac_address = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty(); + // bt_mac must store temporary string - will be valid during send_message call + std::string bluetooth_mac = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty(); + resp.set_bluetooth_mac_address(StringRef(bluetooth_mac)); #endif #ifdef USE_VOICE_ASSISTANT resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags(); @@ -1477,23 +1494,25 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { #endif #ifdef USE_DEVICES for (auto const &device : App.get_devices()) { - DeviceInfo device_info; + resp.devices.emplace_back(); + auto &device_info = resp.devices.back(); device_info.device_id = device->get_device_id(); - device_info.name = device->get_name(); + device_info.set_name(StringRef(device->get_name())); device_info.area_id = device->get_area_id(); - resp.devices.push_back(device_info); } #endif #ifdef USE_AREAS for (auto const &area : App.get_areas()) { - AreaInfo area_info; + resp.areas.emplace_back(); + auto &area_info = resp.areas.back(); area_info.area_id = area->get_area_id(); - area_info.name = area->get_name(); - resp.areas.push_back(area_info); + area_info.set_name(StringRef(area->get_name())); } #endif - return resp; + + return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE); } + void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) { for (auto &it : this->parent_->get_state_subs()) { if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) { @@ -1515,23 +1534,21 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) { } #endif #ifdef USE_API_NOISE -NoiseEncryptionSetKeyResponse APIConnection::noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) { +bool APIConnection::send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) { psk_t psk{}; NoiseEncryptionSetKeyResponse resp; if (base64_decode(msg.key, psk.data(), msg.key.size()) != psk.size()) { ESP_LOGW(TAG, "Invalid encryption key length"); resp.success = false; - return resp; + return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE); } - if (!this->parent_->save_noise_psk(psk, true)) { ESP_LOGW(TAG, "Failed to save encryption key"); resp.success = false; - return resp; + return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE); } - resp.success = true; - return resp; + return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE); } #endif void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index de7e91de01..5365a48292 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -148,8 +148,7 @@ class APIConnection : public APIServerConnection { void bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) override; void bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) override; void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) override; - BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( - const SubscribeBluetoothConnectionsFreeRequest &msg) override; + bool send_subscribe_bluetooth_connections_free_response(const SubscribeBluetoothConnectionsFreeRequest &msg) override; void bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) override; #endif @@ -167,8 +166,7 @@ class APIConnection : public APIServerConnection { void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override; void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override; void on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) override; - VoiceAssistantConfigurationResponse voice_assistant_get_configuration( - const VoiceAssistantConfigurationRequest &msg) override; + bool send_voice_assistant_get_configuration_response(const VoiceAssistantConfigurationRequest &msg) override; void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override; #endif @@ -195,11 +193,11 @@ class APIConnection : public APIServerConnection { #ifdef USE_HOMEASSISTANT_TIME void on_get_time_response(const GetTimeResponse &value) override; #endif - HelloResponse hello(const HelloRequest &msg) override; - ConnectResponse connect(const ConnectRequest &msg) override; - DisconnectResponse disconnect(const DisconnectRequest &msg) override; - PingResponse ping(const PingRequest &msg) override { return {}; } - DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; + bool send_hello_response(const HelloRequest &msg) override; + bool send_connect_response(const ConnectRequest &msg) override; + bool send_disconnect_response(const DisconnectRequest &msg) override; + bool send_ping_response(const PingRequest &msg) override; + bool send_device_info_response(const DeviceInfoRequest &msg) override; void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } void subscribe_states(const SubscribeStatesRequest &msg) override { this->flags_.state_subscription = true; @@ -214,15 +212,12 @@ class APIConnection : public APIServerConnection { this->flags_.service_call_subscription = true; } void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override; - GetTimeResponse get_time(const GetTimeRequest &msg) override { - // TODO - return {}; - } + bool send_get_time_response(const GetTimeRequest &msg) override; #ifdef USE_API_SERVICES void execute_service(const ExecuteServiceRequest &msg) override; #endif #ifdef USE_API_NOISE - NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override; + bool send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) override; #endif bool is_authenticated() override { @@ -313,14 +308,17 @@ class APIConnection : public APIServerConnection { APIConnection *conn, uint32_t remaining_size, bool is_single) { // Set common fields that are shared by all entity types msg.key = entity->get_object_id_hash(); - msg.object_id = entity->get_object_id(); + // IMPORTANT: get_object_id() may return a temporary std::string + std::string object_id = entity->get_object_id(); + msg.set_object_id(StringRef(object_id)); - if (entity->has_own_name()) - msg.name = entity->get_name(); + if (entity->has_own_name()) { + msg.set_name(entity->get_name()); + } - // Set common EntityBase properties + // Set common EntityBase properties #ifdef USE_ENTITY_ICON - msg.icon = entity->get_icon(); + msg.set_icon(entity->get_icon_ref()); #endif msg.disabled_by_default = entity->is_disabled_by_default(); msg.entity_category = static_cast(entity->get_entity_category()); diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index 3c2c9e059e..dcb9de9c93 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -15,6 +15,7 @@ namespace api { static const char *const TAG = "api.noise"; static const char *const PROLOGUE_INIT = "NoiseAPIInit"; +static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit") #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->client_info_->get_combined_info().c_str(), ##__VA_ARGS__) @@ -73,7 +74,9 @@ APIError APINoiseFrameHelper::init() { } // init prologue - prologue_.insert(prologue_.end(), PROLOGUE_INIT, PROLOGUE_INIT + strlen(PROLOGUE_INIT)); + size_t old_size = prologue_.size(); + prologue_.resize(old_size + PROLOGUE_INIT_LEN); + std::memcpy(prologue_.data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN); state_ = State::CLIENT_HELLO; return APIError::OK; @@ -223,11 +226,12 @@ APIError APINoiseFrameHelper::state_action_() { return handle_handshake_frame_error_(aerr); } // ignore contents, may be used in future for flags - // Reserve space for: existing prologue + 2 size bytes + frame data - prologue_.reserve(prologue_.size() + 2 + frame.size()); - prologue_.push_back((uint8_t) (frame.size() >> 8)); - prologue_.push_back((uint8_t) frame.size()); - prologue_.insert(prologue_.end(), frame.begin(), frame.end()); + // Resize for: existing prologue + 2 size bytes + frame data + size_t old_size = prologue_.size(); + prologue_.resize(old_size + 2 + frame.size()); + prologue_[old_size] = (uint8_t) (frame.size() >> 8); + prologue_[old_size + 1] = (uint8_t) frame.size(); + std::memcpy(prologue_.data() + old_size + 2, frame.data(), frame.size()); state_ = State::SERVER_HELLO; } @@ -237,18 +241,22 @@ APIError APINoiseFrameHelper::state_action_() { const std::string &mac = get_mac_address(); std::vector msg; - // Reserve space for: 1 byte proto + name + null + mac + null - msg.reserve(1 + name.size() + 1 + mac.size() + 1); + // Calculate positions and sizes + size_t name_len = name.size() + 1; // including null terminator + size_t mac_len = mac.size() + 1; // including null terminator + size_t name_offset = 1; + size_t mac_offset = name_offset + name_len; + size_t total_size = 1 + name_len + mac_len; + + msg.resize(total_size); // chosen proto - msg.push_back(0x01); + msg[0] = 0x01; // node name, terminated by null byte - const uint8_t *name_ptr = reinterpret_cast(name.c_str()); - msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1); + std::memcpy(msg.data() + name_offset, name.c_str(), name_len); // node mac, terminated by null byte - const uint8_t *mac_ptr = reinterpret_cast(mac.c_str()); - msg.insert(msg.end(), mac_ptr, mac_ptr + mac.size() + 1); + std::memcpy(msg.data() + mac_offset, mac.c_str(), mac_len); aerr = write_frame_(msg.data(), msg.size()); if (aerr != APIError::OK) diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 528c581ad7..d51f641746 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -34,14 +34,14 @@ bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) void HelloResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(1, this->api_version_major); buffer.encode_uint32(2, this->api_version_minor); - buffer.encode_string(3, this->server_info); - buffer.encode_string(4, this->name); + buffer.encode_string(3, this->server_info_ref_); + buffer.encode_string(4, this->name_ref_); } void HelloResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->api_version_major); ProtoSize::add_uint32_field(total_size, 1, this->api_version_minor); - ProtoSize::add_string_field(total_size, 1, this->server_info); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->server_info_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); } bool ConnectRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { @@ -60,22 +60,22 @@ void ConnectResponse::calculate_size(uint32_t &total_size) const { #ifdef USE_AREAS void AreaInfo::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(1, this->area_id); - buffer.encode_string(2, this->name); + buffer.encode_string(2, this->name_ref_); } void AreaInfo::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->area_id); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); } #endif #ifdef USE_DEVICES void DeviceInfo::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(1, this->device_id); - buffer.encode_string(2, this->name); + buffer.encode_string(2, this->name_ref_); buffer.encode_uint32(3, this->area_id); } void DeviceInfo::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint32_field(total_size, 1, this->device_id); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_uint32_field(total_size, 1, this->area_id); } #endif @@ -83,19 +83,19 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { #ifdef USE_API_PASSWORD buffer.encode_bool(1, this->uses_password); #endif - buffer.encode_string(2, this->name); - buffer.encode_string(3, this->mac_address); - buffer.encode_string(4, this->esphome_version); - buffer.encode_string(5, this->compilation_time); - buffer.encode_string(6, this->model); + buffer.encode_string(2, this->name_ref_); + buffer.encode_string(3, this->mac_address_ref_); + buffer.encode_string(4, this->esphome_version_ref_); + buffer.encode_string(5, this->compilation_time_ref_); + buffer.encode_string(6, this->model_ref_); #ifdef USE_DEEP_SLEEP buffer.encode_bool(7, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME - buffer.encode_string(8, this->project_name); + buffer.encode_string(8, this->project_name_ref_); #endif #ifdef ESPHOME_PROJECT_NAME - buffer.encode_string(9, this->project_version); + buffer.encode_string(9, this->project_version_ref_); #endif #ifdef USE_WEBSERVER buffer.encode_uint32(10, this->webserver_port); @@ -103,16 +103,16 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { #ifdef USE_BLUETOOTH_PROXY buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags); #endif - buffer.encode_string(12, this->manufacturer); - buffer.encode_string(13, this->friendly_name); + buffer.encode_string(12, this->manufacturer_ref_); + buffer.encode_string(13, this->friendly_name_ref_); #ifdef USE_VOICE_ASSISTANT buffer.encode_uint32(17, this->voice_assistant_feature_flags); #endif #ifdef USE_AREAS - buffer.encode_string(16, this->suggested_area); + buffer.encode_string(16, this->suggested_area_ref_); #endif #ifdef USE_BLUETOOTH_PROXY - buffer.encode_string(18, this->bluetooth_mac_address); + buffer.encode_string(18, this->bluetooth_mac_address_ref_); #endif #ifdef USE_API_NOISE buffer.encode_bool(19, this->api_encryption_supported); @@ -135,19 +135,19 @@ void DeviceInfoResponse::calculate_size(uint32_t &total_size) const { #ifdef USE_API_PASSWORD ProtoSize::add_bool_field(total_size, 1, this->uses_password); #endif - ProtoSize::add_string_field(total_size, 1, this->name); - ProtoSize::add_string_field(total_size, 1, this->mac_address); - ProtoSize::add_string_field(total_size, 1, this->esphome_version); - ProtoSize::add_string_field(total_size, 1, this->compilation_time); - ProtoSize::add_string_field(total_size, 1, this->model); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->mac_address_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->esphome_version_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->compilation_time_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->model_ref_.size()); #ifdef USE_DEEP_SLEEP ProtoSize::add_bool_field(total_size, 1, this->has_deep_sleep); #endif #ifdef ESPHOME_PROJECT_NAME - ProtoSize::add_string_field(total_size, 1, this->project_name); + ProtoSize::add_string_field(total_size, 1, this->project_name_ref_.size()); #endif #ifdef ESPHOME_PROJECT_NAME - ProtoSize::add_string_field(total_size, 1, this->project_version); + ProtoSize::add_string_field(total_size, 1, this->project_version_ref_.size()); #endif #ifdef USE_WEBSERVER ProtoSize::add_uint32_field(total_size, 1, this->webserver_port); @@ -155,16 +155,16 @@ void DeviceInfoResponse::calculate_size(uint32_t &total_size) const { #ifdef USE_BLUETOOTH_PROXY ProtoSize::add_uint32_field(total_size, 1, this->bluetooth_proxy_feature_flags); #endif - ProtoSize::add_string_field(total_size, 1, this->manufacturer); - ProtoSize::add_string_field(total_size, 1, this->friendly_name); + ProtoSize::add_string_field(total_size, 1, this->manufacturer_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->friendly_name_ref_.size()); #ifdef USE_VOICE_ASSISTANT ProtoSize::add_uint32_field(total_size, 2, this->voice_assistant_feature_flags); #endif #ifdef USE_AREAS - ProtoSize::add_string_field(total_size, 2, this->suggested_area); + ProtoSize::add_string_field(total_size, 2, this->suggested_area_ref_.size()); #endif #ifdef USE_BLUETOOTH_PROXY - ProtoSize::add_string_field(total_size, 2, this->bluetooth_mac_address); + ProtoSize::add_string_field(total_size, 2, this->bluetooth_mac_address_ref_.size()); #endif #ifdef USE_API_NOISE ProtoSize::add_bool_field(total_size, 2, this->api_encryption_supported); @@ -181,14 +181,14 @@ void DeviceInfoResponse::calculate_size(uint32_t &total_size) const { } #ifdef USE_BINARY_SENSOR void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); - buffer.encode_string(5, this->device_class); + buffer.encode_string(3, this->name_ref_); + buffer.encode_string(5, this->device_class_ref_); buffer.encode_bool(6, this->is_status_binary_sensor); buffer.encode_bool(7, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(8, this->icon); + buffer.encode_string(8, this->icon_ref_); #endif buffer.encode_uint32(9, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -196,14 +196,14 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesBinarySensorResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->is_status_binary_sensor); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -229,16 +229,16 @@ void BinarySensorStateResponse::calculate_size(uint32_t &total_size) const { #endif #ifdef USE_COVER void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); buffer.encode_bool(5, this->assumed_state); buffer.encode_bool(6, this->supports_position); buffer.encode_bool(7, this->supports_tilt); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); buffer.encode_bool(9, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(10, this->icon); + buffer.encode_string(10, this->icon_ref_); #endif buffer.encode_uint32(11, static_cast(this->entity_category)); buffer.encode_bool(12, this->supports_stop); @@ -247,16 +247,16 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesCoverResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->assumed_state); ProtoSize::add_bool_field(total_size, 1, this->supports_position); ProtoSize::add_bool_field(total_size, 1, this->supports_tilt); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); ProtoSize::add_bool_field(total_size, 1, this->supports_stop); @@ -322,16 +322,16 @@ bool CoverCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_FAN void ListEntitiesFanResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); buffer.encode_bool(5, this->supports_oscillation); buffer.encode_bool(6, this->supports_speed); buffer.encode_bool(7, this->supports_direction); buffer.encode_int32(8, this->supported_speed_count); buffer.encode_bool(9, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(10, this->icon); + buffer.encode_string(10, this->icon_ref_); #endif buffer.encode_uint32(11, static_cast(this->entity_category)); for (auto &it : this->supported_preset_modes) { @@ -342,16 +342,16 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesFanResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->supports_oscillation); ProtoSize::add_bool_field(total_size, 1, this->supports_speed); ProtoSize::add_bool_field(total_size, 1, this->supports_direction); ProtoSize::add_int32_field(total_size, 1, this->supported_speed_count); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); if (!this->supported_preset_modes.empty()) { @@ -369,7 +369,7 @@ void FanStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(3, this->oscillating); buffer.encode_uint32(5, static_cast(this->direction)); buffer.encode_int32(6, this->speed_level); - buffer.encode_string(7, this->preset_mode); + buffer.encode_string(7, this->preset_mode_ref_); #ifdef USE_DEVICES buffer.encode_uint32(8, this->device_id); #endif @@ -380,7 +380,7 @@ void FanStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->oscillating); ProtoSize::add_enum_field(total_size, 1, static_cast(this->direction)); ProtoSize::add_int32_field(total_size, 1, this->speed_level); - ProtoSize::add_string_field(total_size, 1, this->preset_mode); + ProtoSize::add_string_field(total_size, 1, this->preset_mode_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -447,9 +447,9 @@ bool FanCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_LIGHT void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); for (auto &it : this->supported_color_modes) { buffer.encode_uint32(12, static_cast(it), true); } @@ -460,7 +460,7 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const { } buffer.encode_bool(13, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(14, this->icon); + buffer.encode_string(14, this->icon_ref_); #endif buffer.encode_uint32(15, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -468,9 +468,9 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesLightResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); if (!this->supported_color_modes.empty()) { for (const auto &it : this->supported_color_modes) { ProtoSize::add_enum_field_repeated(total_size, 1, static_cast(it)); @@ -485,7 +485,7 @@ void ListEntitiesLightResponse::calculate_size(uint32_t &total_size) const { } ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -505,7 +505,7 @@ void LightStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_float(8, this->color_temperature); buffer.encode_float(12, this->cold_white); buffer.encode_float(13, this->warm_white); - buffer.encode_string(9, this->effect); + buffer.encode_string(9, this->effect_ref_); #ifdef USE_DEVICES buffer.encode_uint32(14, this->device_id); #endif @@ -523,7 +523,7 @@ void LightStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_float_field(total_size, 1, this->color_temperature); ProtoSize::add_float_field(total_size, 1, this->cold_white); ProtoSize::add_float_field(total_size, 1, this->warm_white); - ProtoSize::add_string_field(total_size, 1, this->effect); + ProtoSize::add_string_field(total_size, 1, this->effect_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -638,16 +638,16 @@ bool LightCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_SENSOR void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif - buffer.encode_string(6, this->unit_of_measurement); + buffer.encode_string(6, this->unit_of_measurement_ref_); buffer.encode_int32(7, this->accuracy_decimals); buffer.encode_bool(8, this->force_update); - buffer.encode_string(9, this->device_class); + buffer.encode_string(9, this->device_class_ref_); buffer.encode_uint32(10, static_cast(this->state_class)); buffer.encode_bool(12, this->disabled_by_default); buffer.encode_uint32(13, static_cast(this->entity_category)); @@ -656,16 +656,16 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesSensorResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif - ProtoSize::add_string_field(total_size, 1, this->unit_of_measurement); + ProtoSize::add_string_field(total_size, 1, this->unit_of_measurement_ref_.size()); ProtoSize::add_int32_field(total_size, 1, this->accuracy_decimals); ProtoSize::add_bool_field(total_size, 1, this->force_update); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); ProtoSize::add_enum_field(total_size, 1, static_cast(this->state_class)); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -692,31 +692,31 @@ void SensorStateResponse::calculate_size(uint32_t &total_size) const { #endif #ifdef USE_SWITCH void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->assumed_state); buffer.encode_bool(7, this->disabled_by_default); buffer.encode_uint32(8, static_cast(this->entity_category)); - buffer.encode_string(9, this->device_class); + buffer.encode_string(9, this->device_class_ref_); #ifdef USE_DEVICES buffer.encode_uint32(10, this->device_id); #endif } void ListEntitiesSwitchResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->assumed_state); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -763,36 +763,36 @@ bool SwitchCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_TEXT_SENSOR void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); #ifdef USE_DEVICES buffer.encode_uint32(9, this->device_id); #endif } void ListEntitiesTextSensorResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif } void TextSensorStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->state); + buffer.encode_string(2, this->state_ref_); buffer.encode_bool(3, this->missing_state); #ifdef USE_DEVICES buffer.encode_uint32(4, this->device_id); @@ -800,7 +800,7 @@ void TextSensorStateResponse::encode(ProtoWriteBuffer buffer) const { } void TextSensorStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->state); + ProtoSize::add_string_field(total_size, 1, this->state_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->missing_state); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); @@ -822,13 +822,11 @@ bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { } void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(1, static_cast(this->level)); - buffer.encode_bytes(3, reinterpret_cast(this->message.data()), this->message.size()); - buffer.encode_bool(4, this->send_failed); + buffer.encode_bytes(3, this->message_ptr_, this->message_len_); } void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->level)); - ProtoSize::add_string_field(total_size, 1, this->message); - ProtoSize::add_bool_field(total_size, 1, this->send_failed); + ProtoSize::add_bytes_field(total_size, 1, this->message_len_); } #ifdef USE_API_NOISE bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -847,15 +845,15 @@ void NoiseEncryptionSetKeyResponse::calculate_size(uint32_t &total_size) const { } #endif void HomeassistantServiceMap::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->key); - buffer.encode_string(2, this->value); + buffer.encode_string(1, this->key_ref_); + buffer.encode_string(2, this->value_ref_); } void HomeassistantServiceMap::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->value); + ProtoSize::add_string_field(total_size, 1, this->key_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->value_ref_.size()); } void HomeassistantServiceResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->service); + buffer.encode_string(1, this->service_ref_); for (auto &it : this->data) { buffer.encode_message(2, it, true); } @@ -868,20 +866,20 @@ void HomeassistantServiceResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(5, this->is_event); } void HomeassistantServiceResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->service); + ProtoSize::add_string_field(total_size, 1, this->service_ref_.size()); ProtoSize::add_repeated_message(total_size, 1, this->data); ProtoSize::add_repeated_message(total_size, 1, this->data_template); ProtoSize::add_repeated_message(total_size, 1, this->variables); ProtoSize::add_bool_field(total_size, 1, this->is_event); } void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->entity_id); - buffer.encode_string(2, this->attribute); + buffer.encode_string(1, this->entity_id_ref_); + buffer.encode_string(2, this->attribute_ref_); buffer.encode_bool(3, this->once); } void SubscribeHomeAssistantStateResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->entity_id); - ProtoSize::add_string_field(total_size, 1, this->attribute); + ProtoSize::add_string_field(total_size, 1, this->entity_id_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->attribute_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->once); } bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { @@ -916,22 +914,22 @@ void GetTimeResponse::calculate_size(uint32_t &total_size) const { } #ifdef USE_API_SERVICES void ListEntitiesServicesArgument::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->name); + buffer.encode_string(1, this->name_ref_); buffer.encode_uint32(2, static_cast(this->type)); } void ListEntitiesServicesArgument::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_enum_field(total_size, 1, static_cast(this->type)); } void ListEntitiesServicesResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->name); + buffer.encode_string(1, this->name_ref_); buffer.encode_fixed32(2, this->key); for (auto &it : this->args) { buffer.encode_message(3, it, true); } } void ListEntitiesServicesResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); ProtoSize::add_repeated_message(total_size, 1, this->args); } @@ -1007,12 +1005,12 @@ bool ExecuteServiceRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_CAMERA void ListEntitiesCameraResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); buffer.encode_bool(5, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(6, this->icon); + buffer.encode_string(6, this->icon_ref_); #endif buffer.encode_uint32(7, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -1020,12 +1018,12 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesCameraResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); #ifdef USE_DEVICES @@ -1034,7 +1032,7 @@ void ListEntitiesCameraResponse::calculate_size(uint32_t &total_size) const { } void CameraImageResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_bytes(2, reinterpret_cast(this->data.data()), this->data.size()); + buffer.encode_bytes(2, this->data_ptr_, this->data_len_); buffer.encode_bool(3, this->done); #ifdef USE_DEVICES buffer.encode_uint32(4, this->device_id); @@ -1042,7 +1040,7 @@ void CameraImageResponse::encode(ProtoWriteBuffer buffer) const { } void CameraImageResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->data); + ProtoSize::add_bytes_field(total_size, 1, this->data_len_); ProtoSize::add_bool_field(total_size, 1, this->done); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); @@ -1064,9 +1062,9 @@ bool CameraImageRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { #endif #ifdef USE_CLIMATE void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); buffer.encode_bool(5, this->supports_current_temperature); buffer.encode_bool(6, this->supports_two_point_target_temperature); for (auto &it : this->supported_modes) { @@ -1093,7 +1091,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const { } buffer.encode_bool(18, this->disabled_by_default); #ifdef USE_ENTITY_ICON - buffer.encode_string(19, this->icon); + buffer.encode_string(19, this->icon_ref_); #endif buffer.encode_uint32(20, static_cast(this->entity_category)); buffer.encode_float(21, this->visual_current_temperature_step); @@ -1106,9 +1104,9 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesClimateResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->supports_current_temperature); ProtoSize::add_bool_field(total_size, 1, this->supports_two_point_target_temperature); if (!this->supported_modes.empty()) { @@ -1147,7 +1145,7 @@ void ListEntitiesClimateResponse::calculate_size(uint32_t &total_size) const { } ProtoSize::add_bool_field(total_size, 2, this->disabled_by_default); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 2, this->icon); + ProtoSize::add_string_field(total_size, 2, this->icon_ref_.size()); #endif ProtoSize::add_enum_field(total_size, 2, static_cast(this->entity_category)); ProtoSize::add_float_field(total_size, 2, this->visual_current_temperature_step); @@ -1169,9 +1167,9 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(8, static_cast(this->action)); buffer.encode_uint32(9, static_cast(this->fan_mode)); buffer.encode_uint32(10, static_cast(this->swing_mode)); - buffer.encode_string(11, this->custom_fan_mode); + buffer.encode_string(11, this->custom_fan_mode_ref_); buffer.encode_uint32(12, static_cast(this->preset)); - buffer.encode_string(13, this->custom_preset); + buffer.encode_string(13, this->custom_preset_ref_); buffer.encode_float(14, this->current_humidity); buffer.encode_float(15, this->target_humidity); #ifdef USE_DEVICES @@ -1188,9 +1186,9 @@ void ClimateStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_enum_field(total_size, 1, static_cast(this->action)); ProtoSize::add_enum_field(total_size, 1, static_cast(this->fan_mode)); ProtoSize::add_enum_field(total_size, 1, static_cast(this->swing_mode)); - ProtoSize::add_string_field(total_size, 1, this->custom_fan_mode); + ProtoSize::add_string_field(total_size, 1, this->custom_fan_mode_ref_.size()); ProtoSize::add_enum_field(total_size, 1, static_cast(this->preset)); - ProtoSize::add_string_field(total_size, 1, this->custom_preset); + ProtoSize::add_string_field(total_size, 1, this->custom_preset_ref_.size()); ProtoSize::add_float_field(total_size, 1, this->current_humidity); ProtoSize::add_float_field(total_size, 1, this->target_humidity); #ifdef USE_DEVICES @@ -1289,39 +1287,39 @@ bool ClimateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_NUMBER void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_float(6, this->min_value); buffer.encode_float(7, this->max_value); buffer.encode_float(8, this->step); buffer.encode_bool(9, this->disabled_by_default); buffer.encode_uint32(10, static_cast(this->entity_category)); - buffer.encode_string(11, this->unit_of_measurement); + buffer.encode_string(11, this->unit_of_measurement_ref_); buffer.encode_uint32(12, static_cast(this->mode)); - buffer.encode_string(13, this->device_class); + buffer.encode_string(13, this->device_class_ref_); #ifdef USE_DEVICES buffer.encode_uint32(14, this->device_id); #endif } void ListEntitiesNumberResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_float_field(total_size, 1, this->min_value); ProtoSize::add_float_field(total_size, 1, this->max_value); ProtoSize::add_float_field(total_size, 1, this->step); ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->unit_of_measurement); + ProtoSize::add_string_field(total_size, 1, this->unit_of_measurement_ref_.size()); ProtoSize::add_enum_field(total_size, 1, static_cast(this->mode)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -1370,11 +1368,11 @@ bool NumberCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_SELECT void ListEntitiesSelectResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif for (auto &it : this->options) { buffer.encode_string(6, it, true); @@ -1386,11 +1384,11 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesSelectResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif if (!this->options.empty()) { for (const auto &it : this->options) { @@ -1405,7 +1403,7 @@ void ListEntitiesSelectResponse::calculate_size(uint32_t &total_size) const { } void SelectStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->state); + buffer.encode_string(2, this->state_ref_); buffer.encode_bool(3, this->missing_state); #ifdef USE_DEVICES buffer.encode_uint32(4, this->device_id); @@ -1413,7 +1411,7 @@ void SelectStateResponse::encode(ProtoWriteBuffer buffer) const { } void SelectStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->state); + ProtoSize::add_string_field(total_size, 1, this->state_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->missing_state); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); @@ -1454,11 +1452,11 @@ bool SelectCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_SIREN void ListEntitiesSirenResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); for (auto &it : this->tones) { @@ -1472,11 +1470,11 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesSirenResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); if (!this->tones.empty()) { @@ -1561,35 +1559,35 @@ bool SirenCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_LOCK void ListEntitiesLockResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); buffer.encode_bool(8, this->assumed_state); buffer.encode_bool(9, this->supports_open); buffer.encode_bool(10, this->requires_code); - buffer.encode_string(11, this->code_format); + buffer.encode_string(11, this->code_format_ref_); #ifdef USE_DEVICES buffer.encode_uint32(12, this->device_id); #endif } void ListEntitiesLockResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); ProtoSize::add_bool_field(total_size, 1, this->assumed_state); ProtoSize::add_bool_field(total_size, 1, this->supports_open); ProtoSize::add_bool_field(total_size, 1, this->requires_code); - ProtoSize::add_string_field(total_size, 1, this->code_format); + ProtoSize::add_string_field(total_size, 1, this->code_format_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -1649,29 +1647,29 @@ bool LockCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_BUTTON void ListEntitiesButtonResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); #ifdef USE_DEVICES buffer.encode_uint32(9, this->device_id); #endif } void ListEntitiesButtonResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -1701,25 +1699,25 @@ bool ButtonCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_MEDIA_PLAYER void MediaPlayerSupportedFormat::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->format); + buffer.encode_string(1, this->format_ref_); buffer.encode_uint32(2, this->sample_rate); buffer.encode_uint32(3, this->num_channels); buffer.encode_uint32(4, static_cast(this->purpose)); buffer.encode_uint32(5, this->sample_bytes); } void MediaPlayerSupportedFormat::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->format); + ProtoSize::add_string_field(total_size, 1, this->format_ref_.size()); ProtoSize::add_uint32_field(total_size, 1, this->sample_rate); ProtoSize::add_uint32_field(total_size, 1, this->num_channels); ProtoSize::add_enum_field(total_size, 1, static_cast(this->purpose)); ProtoSize::add_uint32_field(total_size, 1, this->sample_bytes); } void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); @@ -1732,11 +1730,11 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesMediaPlayerResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -1893,23 +1891,18 @@ bool BluetoothGATTGetServicesRequest::decode_varint(uint32_t field_id, ProtoVarI return true; } void BluetoothGATTDescriptor::encode(ProtoWriteBuffer buffer) const { - for (auto &it : this->uuid) { - buffer.encode_uint64(1, it, true); - } + buffer.encode_uint64(1, this->uuid[0], true); + buffer.encode_uint64(1, this->uuid[1], true); buffer.encode_uint32(2, this->handle); } void BluetoothGATTDescriptor::calculate_size(uint32_t &total_size) const { - if (!this->uuid.empty()) { - for (const auto &it : this->uuid) { - ProtoSize::add_uint64_field_repeated(total_size, 1, it); - } - } + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[0]); + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[1]); ProtoSize::add_uint32_field(total_size, 1, this->handle); } void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer buffer) const { - for (auto &it : this->uuid) { - buffer.encode_uint64(1, it, true); - } + buffer.encode_uint64(1, this->uuid[0], true); + buffer.encode_uint64(1, this->uuid[1], true); buffer.encode_uint32(2, this->handle); buffer.encode_uint32(3, this->properties); for (auto &it : this->descriptors) { @@ -1917,42 +1910,33 @@ void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer buffer) const { } } void BluetoothGATTCharacteristic::calculate_size(uint32_t &total_size) const { - if (!this->uuid.empty()) { - for (const auto &it : this->uuid) { - ProtoSize::add_uint64_field_repeated(total_size, 1, it); - } - } + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[0]); + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[1]); ProtoSize::add_uint32_field(total_size, 1, this->handle); ProtoSize::add_uint32_field(total_size, 1, this->properties); ProtoSize::add_repeated_message(total_size, 1, this->descriptors); } void BluetoothGATTService::encode(ProtoWriteBuffer buffer) const { - for (auto &it : this->uuid) { - buffer.encode_uint64(1, it, true); - } + buffer.encode_uint64(1, this->uuid[0], true); + buffer.encode_uint64(1, this->uuid[1], true); buffer.encode_uint32(2, this->handle); for (auto &it : this->characteristics) { buffer.encode_message(3, it, true); } } void BluetoothGATTService::calculate_size(uint32_t &total_size) const { - if (!this->uuid.empty()) { - for (const auto &it : this->uuid) { - ProtoSize::add_uint64_field_repeated(total_size, 1, it); - } - } + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[0]); + ProtoSize::add_uint64_field_repeated(total_size, 1, this->uuid[1]); ProtoSize::add_uint32_field(total_size, 1, this->handle); ProtoSize::add_repeated_message(total_size, 1, this->characteristics); } void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); - for (auto &it : this->services) { - buffer.encode_message(2, it, true); - } + buffer.encode_message(2, this->services[0], true); } void BluetoothGATTGetServicesResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address); - ProtoSize::add_repeated_message(total_size, 1, this->services); + ProtoSize::add_message_object_repeated(total_size, 1, this->services[0]); } void BluetoothGATTGetServicesDoneResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); @@ -1976,12 +1960,12 @@ bool BluetoothGATTReadRequest::decode_varint(uint32_t field_id, ProtoVarInt valu void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); + buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address); ProtoSize::add_uint32_field(total_size, 1, this->handle); - ProtoSize::add_string_field(total_size, 1, this->data); + ProtoSize::add_bytes_field(total_size, 1, this->data_len_); } bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2064,12 +2048,12 @@ bool BluetoothGATTNotifyRequest::decode_varint(uint32_t field_id, ProtoVarInt va void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint64(1, this->address); buffer.encode_uint32(2, this->handle); - buffer.encode_bytes(3, reinterpret_cast(this->data.data()), this->data.size()); + buffer.encode_bytes(3, this->data_ptr_, this->data_len_); } void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_uint64_field(total_size, 1, this->address); ProtoSize::add_uint32_field(total_size, 1, this->handle); - ProtoSize::add_string_field(total_size, 1, this->data); + ProtoSize::add_bytes_field(total_size, 1, this->data_len_); } void BluetoothConnectionsFreeResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(1, this->free); @@ -2188,17 +2172,17 @@ void VoiceAssistantAudioSettings::calculate_size(uint32_t &total_size) const { } void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); - buffer.encode_string(2, this->conversation_id); + buffer.encode_string(2, this->conversation_id_ref_); buffer.encode_uint32(3, this->flags); buffer.encode_message(4, this->audio_settings); - buffer.encode_string(5, this->wake_word_phrase); + buffer.encode_string(5, this->wake_word_phrase_ref_); } void VoiceAssistantRequest::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->start); - ProtoSize::add_string_field(total_size, 1, this->conversation_id); + ProtoSize::add_string_field(total_size, 1, this->conversation_id_ref_.size()); ProtoSize::add_uint32_field(total_size, 1, this->flags); ProtoSize::add_message_object(total_size, 1, this->audio_settings); - ProtoSize::add_string_field(total_size, 1, this->wake_word_phrase); + ProtoSize::add_string_field(total_size, 1, this->wake_word_phrase_ref_.size()); } bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { @@ -2268,11 +2252,11 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited return true; } void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const { - buffer.encode_bytes(1, reinterpret_cast(this->data.data()), this->data.size()); + buffer.encode_bytes(1, this->data_ptr_, this->data_len_); buffer.encode_bool(2, this->end); } void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->data); + ProtoSize::add_bytes_field(total_size, 1, this->data_len_); ProtoSize::add_bool_field(total_size, 1, this->end); } bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { @@ -2338,15 +2322,15 @@ void VoiceAssistantAnnounceFinished::calculate_size(uint32_t &total_size) const ProtoSize::add_bool_field(total_size, 1, this->success); } void VoiceAssistantWakeWord::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->id); - buffer.encode_string(2, this->wake_word); + buffer.encode_string(1, this->id_ref_); + buffer.encode_string(2, this->wake_word_ref_); for (auto &it : this->trained_languages) { buffer.encode_string(3, it, true); } } void VoiceAssistantWakeWord::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->id); - ProtoSize::add_string_field(total_size, 1, this->wake_word); + ProtoSize::add_string_field(total_size, 1, this->id_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->wake_word_ref_.size()); if (!this->trained_languages.empty()) { for (const auto &it : this->trained_languages) { ProtoSize::add_string_field_repeated(total_size, 1, it); @@ -2384,11 +2368,11 @@ bool VoiceAssistantSetConfiguration::decode_length(uint32_t field_id, ProtoLengt #endif #ifdef USE_ALARM_CONTROL_PANEL void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); @@ -2400,11 +2384,11 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer buffer) cons #endif } void ListEntitiesAlarmControlPanelResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -2467,34 +2451,34 @@ bool AlarmControlPanelCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit #endif #ifdef USE_TEXT void ListEntitiesTextResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); buffer.encode_uint32(8, this->min_length); buffer.encode_uint32(9, this->max_length); - buffer.encode_string(10, this->pattern); + buffer.encode_string(10, this->pattern_ref_); buffer.encode_uint32(11, static_cast(this->mode)); #ifdef USE_DEVICES buffer.encode_uint32(12, this->device_id); #endif } void ListEntitiesTextResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); ProtoSize::add_uint32_field(total_size, 1, this->min_length); ProtoSize::add_uint32_field(total_size, 1, this->max_length); - ProtoSize::add_string_field(total_size, 1, this->pattern); + ProtoSize::add_string_field(total_size, 1, this->pattern_ref_.size()); ProtoSize::add_enum_field(total_size, 1, static_cast(this->mode)); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); @@ -2502,7 +2486,7 @@ void ListEntitiesTextResponse::calculate_size(uint32_t &total_size) const { } void TextStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->state); + buffer.encode_string(2, this->state_ref_); buffer.encode_bool(3, this->missing_state); #ifdef USE_DEVICES buffer.encode_uint32(4, this->device_id); @@ -2510,7 +2494,7 @@ void TextStateResponse::encode(ProtoWriteBuffer buffer) const { } void TextStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->state); + ProtoSize::add_string_field(total_size, 1, this->state_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->missing_state); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); @@ -2551,11 +2535,11 @@ bool TextCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_DATETIME_DATE void ListEntitiesDateResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); @@ -2564,11 +2548,11 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesDateResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -2630,11 +2614,11 @@ bool DateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_DATETIME_TIME void ListEntitiesTimeResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); @@ -2643,11 +2627,11 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesTimeResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -2709,15 +2693,15 @@ bool TimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_EVENT void ListEntitiesEventResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); for (auto &it : this->event_types) { buffer.encode_string(9, it, true); } @@ -2726,15 +2710,15 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesEventResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); if (!this->event_types.empty()) { for (const auto &it : this->event_types) { ProtoSize::add_string_field_repeated(total_size, 1, it); @@ -2746,14 +2730,14 @@ void ListEntitiesEventResponse::calculate_size(uint32_t &total_size) const { } void EventResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_fixed32(1, this->key); - buffer.encode_string(2, this->event_type); + buffer.encode_string(2, this->event_type_ref_); #ifdef USE_DEVICES buffer.encode_uint32(3, this->device_id); #endif } void EventResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->event_type); + ProtoSize::add_string_field(total_size, 1, this->event_type_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -2761,15 +2745,15 @@ void EventResponse::calculate_size(uint32_t &total_size) const { #endif #ifdef USE_VALVE void ListEntitiesValveResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); buffer.encode_bool(9, this->assumed_state); buffer.encode_bool(10, this->supports_position); buffer.encode_bool(11, this->supports_stop); @@ -2778,15 +2762,15 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesValveResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); ProtoSize::add_bool_field(total_size, 1, this->assumed_state); ProtoSize::add_bool_field(total_size, 1, this->supports_position); ProtoSize::add_bool_field(total_size, 1, this->supports_stop); @@ -2844,11 +2828,11 @@ bool ValveCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_DATETIME_DATETIME void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); @@ -2857,11 +2841,11 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer buffer) const { #endif } void ListEntitiesDateTimeResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); @@ -2913,29 +2897,29 @@ bool DateTimeCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) { #endif #ifdef USE_UPDATE void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer buffer) const { - buffer.encode_string(1, this->object_id); + buffer.encode_string(1, this->object_id_ref_); buffer.encode_fixed32(2, this->key); - buffer.encode_string(3, this->name); + buffer.encode_string(3, this->name_ref_); #ifdef USE_ENTITY_ICON - buffer.encode_string(5, this->icon); + buffer.encode_string(5, this->icon_ref_); #endif buffer.encode_bool(6, this->disabled_by_default); buffer.encode_uint32(7, static_cast(this->entity_category)); - buffer.encode_string(8, this->device_class); + buffer.encode_string(8, this->device_class_ref_); #ifdef USE_DEVICES buffer.encode_uint32(9, this->device_id); #endif } void ListEntitiesUpdateResponse::calculate_size(uint32_t &total_size) const { - ProtoSize::add_string_field(total_size, 1, this->object_id); + ProtoSize::add_string_field(total_size, 1, this->object_id_ref_.size()); ProtoSize::add_fixed32_field(total_size, 1, this->key); - ProtoSize::add_string_field(total_size, 1, this->name); + ProtoSize::add_string_field(total_size, 1, this->name_ref_.size()); #ifdef USE_ENTITY_ICON - ProtoSize::add_string_field(total_size, 1, this->icon); + ProtoSize::add_string_field(total_size, 1, this->icon_ref_.size()); #endif ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default); ProtoSize::add_enum_field(total_size, 1, static_cast(this->entity_category)); - ProtoSize::add_string_field(total_size, 1, this->device_class); + ProtoSize::add_string_field(total_size, 1, this->device_class_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif @@ -2946,11 +2930,11 @@ void UpdateStateResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(3, this->in_progress); buffer.encode_bool(4, this->has_progress); buffer.encode_float(5, this->progress); - buffer.encode_string(6, this->current_version); - buffer.encode_string(7, this->latest_version); - buffer.encode_string(8, this->title); - buffer.encode_string(9, this->release_summary); - buffer.encode_string(10, this->release_url); + buffer.encode_string(6, this->current_version_ref_); + buffer.encode_string(7, this->latest_version_ref_); + buffer.encode_string(8, this->title_ref_); + buffer.encode_string(9, this->release_summary_ref_); + buffer.encode_string(10, this->release_url_ref_); #ifdef USE_DEVICES buffer.encode_uint32(11, this->device_id); #endif @@ -2961,11 +2945,11 @@ void UpdateStateResponse::calculate_size(uint32_t &total_size) const { ProtoSize::add_bool_field(total_size, 1, this->in_progress); ProtoSize::add_bool_field(total_size, 1, this->has_progress); ProtoSize::add_float_field(total_size, 1, this->progress); - ProtoSize::add_string_field(total_size, 1, this->current_version); - ProtoSize::add_string_field(total_size, 1, this->latest_version); - ProtoSize::add_string_field(total_size, 1, this->title); - ProtoSize::add_string_field(total_size, 1, this->release_summary); - ProtoSize::add_string_field(total_size, 1, this->release_url); + ProtoSize::add_string_field(total_size, 1, this->current_version_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->latest_version_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->title_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->release_summary_ref_.size()); + ProtoSize::add_string_field(total_size, 1, this->release_url_ref_.size()); #ifdef USE_DEVICES ProtoSize::add_uint32_field(total_size, 1, this->device_id); #endif diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 7b64bd889f..9bf50fd18b 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -3,6 +3,7 @@ #pragma once #include "esphome/core/defines.h" +#include "esphome/core/string_ref.h" #include "proto.h" @@ -269,12 +270,15 @@ enum UpdateCommand : uint32_t { class InfoResponseProtoMessage : public ProtoMessage { public: ~InfoResponseProtoMessage() override = default; - std::string object_id{}; + StringRef object_id_ref_{}; + void set_object_id(const StringRef &ref) { this->object_id_ref_ = ref; } uint32_t key{0}; - std::string name{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } bool disabled_by_default{false}; #ifdef USE_ENTITY_ICON - std::string icon{}; + StringRef icon_ref_{}; + void set_icon(const StringRef &ref) { this->icon_ref_ = ref; } #endif enums::EntityCategory entity_category{}; #ifdef USE_DEVICES @@ -332,8 +336,10 @@ class HelloResponse : public ProtoMessage { #endif uint32_t api_version_major{0}; uint32_t api_version_minor{0}; - std::string server_info{}; - std::string name{}; + StringRef server_info_ref_{}; + void set_server_info(const StringRef &ref) { this->server_info_ref_ = ref; } + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -442,7 +448,8 @@ class DeviceInfoRequest : public ProtoDecodableMessage { class AreaInfo : public ProtoMessage { public: uint32_t area_id{0}; - std::string name{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -456,7 +463,8 @@ class AreaInfo : public ProtoMessage { class DeviceInfo : public ProtoMessage { public: uint32_t device_id{0}; - std::string name{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } uint32_t area_id{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -477,19 +485,26 @@ class DeviceInfoResponse : public ProtoMessage { #ifdef USE_API_PASSWORD bool uses_password{false}; #endif - std::string name{}; - std::string mac_address{}; - std::string esphome_version{}; - std::string compilation_time{}; - std::string model{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } + StringRef mac_address_ref_{}; + void set_mac_address(const StringRef &ref) { this->mac_address_ref_ = ref; } + StringRef esphome_version_ref_{}; + void set_esphome_version(const StringRef &ref) { this->esphome_version_ref_ = ref; } + StringRef compilation_time_ref_{}; + void set_compilation_time(const StringRef &ref) { this->compilation_time_ref_ = ref; } + StringRef model_ref_{}; + void set_model(const StringRef &ref) { this->model_ref_ = ref; } #ifdef USE_DEEP_SLEEP bool has_deep_sleep{false}; #endif #ifdef ESPHOME_PROJECT_NAME - std::string project_name{}; + StringRef project_name_ref_{}; + void set_project_name(const StringRef &ref) { this->project_name_ref_ = ref; } #endif #ifdef ESPHOME_PROJECT_NAME - std::string project_version{}; + StringRef project_version_ref_{}; + void set_project_version(const StringRef &ref) { this->project_version_ref_ = ref; } #endif #ifdef USE_WEBSERVER uint32_t webserver_port{0}; @@ -497,16 +512,20 @@ class DeviceInfoResponse : public ProtoMessage { #ifdef USE_BLUETOOTH_PROXY uint32_t bluetooth_proxy_feature_flags{0}; #endif - std::string manufacturer{}; - std::string friendly_name{}; + StringRef manufacturer_ref_{}; + void set_manufacturer(const StringRef &ref) { this->manufacturer_ref_ = ref; } + StringRef friendly_name_ref_{}; + void set_friendly_name(const StringRef &ref) { this->friendly_name_ref_ = ref; } #ifdef USE_VOICE_ASSISTANT uint32_t voice_assistant_feature_flags{0}; #endif #ifdef USE_AREAS - std::string suggested_area{}; + StringRef suggested_area_ref_{}; + void set_suggested_area(const StringRef &ref) { this->suggested_area_ref_ = ref; } #endif #ifdef USE_BLUETOOTH_PROXY - std::string bluetooth_mac_address{}; + StringRef bluetooth_mac_address_ref_{}; + void set_bluetooth_mac_address(const StringRef &ref) { this->bluetooth_mac_address_ref_ = ref; } #endif #ifdef USE_API_NOISE bool api_encryption_supported{false}; @@ -575,7 +594,8 @@ class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_binary_sensor_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } bool is_status_binary_sensor{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -614,7 +634,8 @@ class ListEntitiesCoverResponse : public InfoResponseProtoMessage { bool assumed_state{false}; bool supports_position{false}; bool supports_tilt{false}; - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } bool supports_stop{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -695,7 +716,8 @@ class FanStateResponse : public StateResponseProtoMessage { bool oscillating{false}; enums::FanDirection direction{}; int32_t speed_level{0}; - std::string preset_mode{}; + StringRef preset_mode_ref_{}; + void set_preset_mode(const StringRef &ref) { this->preset_mode_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -769,7 +791,8 @@ class LightStateResponse : public StateResponseProtoMessage { float color_temperature{0.0f}; float cold_white{0.0f}; float warm_white{0.0f}; - std::string effect{}; + StringRef effect_ref_{}; + void set_effect(const StringRef &ref) { this->effect_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -829,10 +852,12 @@ class ListEntitiesSensorResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_sensor_response"; } #endif - std::string unit_of_measurement{}; + StringRef unit_of_measurement_ref_{}; + void set_unit_of_measurement(const StringRef &ref) { this->unit_of_measurement_ref_ = ref; } int32_t accuracy_decimals{0}; bool force_update{false}; - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } enums::SensorStateClass state_class{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -869,7 +894,8 @@ class ListEntitiesSwitchResponse : public InfoResponseProtoMessage { const char *message_name() const override { return "list_entities_switch_response"; } #endif bool assumed_state{false}; - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -919,7 +945,8 @@ class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_text_sensor_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -935,7 +962,8 @@ class TextSensorStateResponse : public StateResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "text_sensor_state_response"; } #endif - std::string state{}; + StringRef state_ref_{}; + void set_state(const StringRef &ref) { this->state_ref_ = ref; } bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -965,13 +993,17 @@ class SubscribeLogsRequest : public ProtoDecodableMessage { class SubscribeLogsResponse : public ProtoMessage { public: static constexpr uint8_t MESSAGE_TYPE = 29; - static constexpr uint8_t ESTIMATED_SIZE = 13; + static constexpr uint8_t ESTIMATED_SIZE = 11; #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "subscribe_logs_response"; } #endif enums::LogLevel level{}; - std::string message{}; - bool send_failed{false}; + const uint8_t *message_ptr_{nullptr}; + size_t message_len_{0}; + void set_message(const uint8_t *data, size_t len) { + this->message_ptr_ = data; + this->message_len_ = len; + } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1028,8 +1060,10 @@ class SubscribeHomeassistantServicesRequest : public ProtoDecodableMessage { }; class HomeassistantServiceMap : public ProtoMessage { public: - std::string key{}; - std::string value{}; + StringRef key_ref_{}; + void set_key(const StringRef &ref) { this->key_ref_ = ref; } + StringRef value_ref_{}; + void set_value(const StringRef &ref) { this->value_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1045,7 +1079,8 @@ class HomeassistantServiceResponse : public ProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "homeassistant_service_response"; } #endif - std::string service{}; + StringRef service_ref_{}; + void set_service(const StringRef &ref) { this->service_ref_ = ref; } std::vector data{}; std::vector data_template{}; std::vector variables{}; @@ -1078,8 +1113,10 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "subscribe_home_assistant_state_response"; } #endif - std::string entity_id{}; - std::string attribute{}; + StringRef entity_id_ref_{}; + void set_entity_id(const StringRef &ref) { this->entity_id_ref_ = ref; } + StringRef attribute_ref_{}; + void set_attribute(const StringRef &ref) { this->attribute_ref_ = ref; } bool once{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1139,7 +1176,8 @@ class GetTimeResponse : public ProtoDecodableMessage { #ifdef USE_API_SERVICES class ListEntitiesServicesArgument : public ProtoMessage { public: - std::string name{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } enums::ServiceArgType type{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1156,7 +1194,8 @@ class ListEntitiesServicesResponse : public ProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_services_response"; } #endif - std::string name{}; + StringRef name_ref_{}; + void set_name(const StringRef &ref) { this->name_ref_ = ref; } uint32_t key{0}; std::vector args{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1228,7 +1267,12 @@ class CameraImageResponse : public StateResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "camera_image_response"; } #endif - std::string data{}; + const uint8_t *data_ptr_{nullptr}; + size_t data_len_{0}; + void set_data(const uint8_t *data, size_t len) { + this->data_ptr_ = data; + this->data_len_ = len; + } bool done{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1303,9 +1347,11 @@ class ClimateStateResponse : public StateResponseProtoMessage { enums::ClimateAction action{}; enums::ClimateFanMode fan_mode{}; enums::ClimateSwingMode swing_mode{}; - std::string custom_fan_mode{}; + StringRef custom_fan_mode_ref_{}; + void set_custom_fan_mode(const StringRef &ref) { this->custom_fan_mode_ref_ = ref; } enums::ClimatePreset preset{}; - std::string custom_preset{}; + StringRef custom_preset_ref_{}; + void set_custom_preset(const StringRef &ref) { this->custom_preset_ref_ = ref; } float current_humidity{0.0f}; float target_humidity{0.0f}; void encode(ProtoWriteBuffer buffer) const override; @@ -1364,9 +1410,11 @@ class ListEntitiesNumberResponse : public InfoResponseProtoMessage { float min_value{0.0f}; float max_value{0.0f}; float step{0.0f}; - std::string unit_of_measurement{}; + StringRef unit_of_measurement_ref_{}; + void set_unit_of_measurement(const StringRef &ref) { this->unit_of_measurement_ref_ = ref; } enums::NumberMode mode{}; - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1433,7 +1481,8 @@ class SelectStateResponse : public StateResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "select_state_response"; } #endif - std::string state{}; + StringRef state_ref_{}; + void set_state(const StringRef &ref) { this->state_ref_ = ref; } bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1532,7 +1581,8 @@ class ListEntitiesLockResponse : public InfoResponseProtoMessage { bool assumed_state{false}; bool supports_open{false}; bool requires_code{false}; - std::string code_format{}; + StringRef code_format_ref_{}; + void set_code_format(const StringRef &ref) { this->code_format_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1585,7 +1635,8 @@ class ListEntitiesButtonResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_button_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1613,7 +1664,8 @@ class ButtonCommandRequest : public CommandProtoMessage { #ifdef USE_MEDIA_PLAYER class MediaPlayerSupportedFormat : public ProtoMessage { public: - std::string format{}; + StringRef format_ref_{}; + void set_format(const StringRef &ref) { this->format_ref_ = ref; } uint32_t sample_rate{0}; uint32_t num_channels{0}; enums::MediaPlayerFormatPurpose purpose{}; @@ -1787,7 +1839,7 @@ class BluetoothGATTGetServicesRequest : public ProtoDecodableMessage { }; class BluetoothGATTDescriptor : public ProtoMessage { public: - std::vector uuid{}; + std::array uuid{}; uint32_t handle{0}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -1799,7 +1851,7 @@ class BluetoothGATTDescriptor : public ProtoMessage { }; class BluetoothGATTCharacteristic : public ProtoMessage { public: - std::vector uuid{}; + std::array uuid{}; uint32_t handle{0}; uint32_t properties{0}; std::vector descriptors{}; @@ -1813,7 +1865,7 @@ class BluetoothGATTCharacteristic : public ProtoMessage { }; class BluetoothGATTService : public ProtoMessage { public: - std::vector uuid{}; + std::array uuid{}; uint32_t handle{0}; std::vector characteristics{}; void encode(ProtoWriteBuffer buffer) const override; @@ -1827,12 +1879,12 @@ class BluetoothGATTService : public ProtoMessage { class BluetoothGATTGetServicesResponse : public ProtoMessage { public: static constexpr uint8_t MESSAGE_TYPE = 71; - static constexpr uint8_t ESTIMATED_SIZE = 38; + static constexpr uint8_t ESTIMATED_SIZE = 21; #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "bluetooth_gatt_get_services_response"; } #endif uint64_t address{0}; - std::vector services{}; + std::array services{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1882,7 +1934,12 @@ class BluetoothGATTReadResponse : public ProtoMessage { #endif uint64_t address{0}; uint32_t handle{0}; - std::string data{}; + const uint8_t *data_ptr_{nullptr}; + size_t data_len_{0}; + void set_data(const uint8_t *data, size_t len) { + this->data_ptr_ = data; + this->data_len_ = len; + } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -1970,7 +2027,12 @@ class BluetoothGATTNotifyDataResponse : public ProtoMessage { #endif uint64_t address{0}; uint32_t handle{0}; - std::string data{}; + const uint8_t *data_ptr_{nullptr}; + size_t data_len_{0}; + void set_data(const uint8_t *data, size_t len) { + this->data_ptr_ = data; + this->data_len_ = len; + } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -2200,10 +2262,12 @@ class VoiceAssistantRequest : public ProtoMessage { const char *message_name() const override { return "voice_assistant_request"; } #endif bool start{false}; - std::string conversation_id{}; + StringRef conversation_id_ref_{}; + void set_conversation_id(const StringRef &ref) { this->conversation_id_ref_ = ref; } uint32_t flags{0}; VoiceAssistantAudioSettings audio_settings{}; - std::string wake_word_phrase{}; + StringRef wake_word_phrase_ref_{}; + void set_wake_word_phrase(const StringRef &ref) { this->wake_word_phrase_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -2264,6 +2328,12 @@ class VoiceAssistantAudio : public ProtoDecodableMessage { const char *message_name() const override { return "voice_assistant_audio"; } #endif std::string data{}; + const uint8_t *data_ptr_{nullptr}; + size_t data_len_{0}; + void set_data(const uint8_t *data, size_t len) { + this->data_ptr_ = data; + this->data_len_ = len; + } bool end{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2333,8 +2403,10 @@ class VoiceAssistantAnnounceFinished : public ProtoMessage { }; class VoiceAssistantWakeWord : public ProtoMessage { public: - std::string id{}; - std::string wake_word{}; + StringRef id_ref_{}; + void set_id(const StringRef &ref) { this->id_ref_ = ref; } + StringRef wake_word_ref_{}; + void set_wake_word(const StringRef &ref) { this->wake_word_ref_ = ref; } std::vector trained_languages{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2455,7 +2527,8 @@ class ListEntitiesTextResponse : public InfoResponseProtoMessage { #endif uint32_t min_length{0}; uint32_t max_length{0}; - std::string pattern{}; + StringRef pattern_ref_{}; + void set_pattern(const StringRef &ref) { this->pattern_ref_ = ref; } enums::TextMode mode{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2472,7 +2545,8 @@ class TextStateResponse : public StateResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "text_state_response"; } #endif - std::string state{}; + StringRef state_ref_{}; + void set_state(const StringRef &ref) { this->state_ref_ = ref; } bool missing_state{false}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2616,7 +2690,8 @@ class ListEntitiesEventResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_event_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } std::vector event_types{}; void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; @@ -2633,7 +2708,8 @@ class EventResponse : public StateResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "event_response"; } #endif - std::string event_type{}; + StringRef event_type_ref_{}; + void set_event_type(const StringRef &ref) { this->event_type_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -2651,7 +2727,8 @@ class ListEntitiesValveResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_valve_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } bool assumed_state{false}; bool supports_position{false}; bool supports_stop{false}; @@ -2757,7 +2834,8 @@ class ListEntitiesUpdateResponse : public InfoResponseProtoMessage { #ifdef HAS_PROTO_MESSAGE_DUMP const char *message_name() const override { return "list_entities_update_response"; } #endif - std::string device_class{}; + StringRef device_class_ref_{}; + void set_device_class(const StringRef &ref) { this->device_class_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -2777,11 +2855,16 @@ class UpdateStateResponse : public StateResponseProtoMessage { bool in_progress{false}; bool has_progress{false}; float progress{0.0f}; - std::string current_version{}; - std::string latest_version{}; - std::string title{}; - std::string release_summary{}; - std::string release_url{}; + StringRef current_version_ref_{}; + void set_current_version(const StringRef &ref) { this->current_version_ref_ = ref; } + StringRef latest_version_ref_{}; + void set_latest_version(const StringRef &ref) { this->latest_version_ref_ = ref; } + StringRef title_ref_{}; + void set_title(const StringRef &ref) { this->title_ref_ = ref; } + StringRef release_summary_ref_{}; + void set_release_summary(const StringRef &ref) { this->release_summary_ref_ = ref; } + StringRef release_url_ref_{}; + void set_release_url(const StringRef &ref) { this->release_url_ref_ = ref; } void encode(ProtoWriteBuffer buffer) const override; void calculate_size(uint32_t &total_size) const override; #ifdef HAS_PROTO_MESSAGE_DUMP diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index 4951c6cebf..4e44bff11e 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -10,6 +10,15 @@ namespace esphome { namespace api { +// Helper function to append a quoted string, handling empty StringRef +static inline void append_quoted_string(std::string &out, const StringRef &ref) { + out.append("'"); + if (!ref.empty()) { + out.append(ref.c_str()); + } + out.append("'"); +} + template<> const char *proto_enum_to_string(enums::EntityCategory value) { switch (value) { case enums::ENTITY_CATEGORY_NONE: @@ -580,11 +589,11 @@ void HelloResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" server_info: "); - out.append("'").append(this->server_info).append("'"); + append_quoted_string(out, this->server_info_ref_); out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append("}"); } @@ -619,7 +628,7 @@ void AreaInfo::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append("}"); } @@ -634,7 +643,7 @@ void DeviceInfo::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" area_id: "); @@ -654,23 +663,23 @@ void DeviceInfoResponse::dump_to(std::string &out) const { #endif out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" mac_address: "); - out.append("'").append(this->mac_address).append("'"); + append_quoted_string(out, this->mac_address_ref_); out.append("\n"); out.append(" esphome_version: "); - out.append("'").append(this->esphome_version).append("'"); + append_quoted_string(out, this->esphome_version_ref_); out.append("\n"); out.append(" compilation_time: "); - out.append("'").append(this->compilation_time).append("'"); + append_quoted_string(out, this->compilation_time_ref_); out.append("\n"); out.append(" model: "); - out.append("'").append(this->model).append("'"); + append_quoted_string(out, this->model_ref_); out.append("\n"); #ifdef USE_DEEP_SLEEP @@ -681,13 +690,13 @@ void DeviceInfoResponse::dump_to(std::string &out) const { #endif #ifdef ESPHOME_PROJECT_NAME out.append(" project_name: "); - out.append("'").append(this->project_name).append("'"); + append_quoted_string(out, this->project_name_ref_); out.append("\n"); #endif #ifdef ESPHOME_PROJECT_NAME out.append(" project_version: "); - out.append("'").append(this->project_version).append("'"); + append_quoted_string(out, this->project_version_ref_); out.append("\n"); #endif @@ -706,11 +715,11 @@ void DeviceInfoResponse::dump_to(std::string &out) const { #endif out.append(" manufacturer: "); - out.append("'").append(this->manufacturer).append("'"); + append_quoted_string(out, this->manufacturer_ref_); out.append("\n"); out.append(" friendly_name: "); - out.append("'").append(this->friendly_name).append("'"); + append_quoted_string(out, this->friendly_name_ref_); out.append("\n"); #ifdef USE_VOICE_ASSISTANT @@ -722,13 +731,13 @@ void DeviceInfoResponse::dump_to(std::string &out) const { #endif #ifdef USE_AREAS out.append(" suggested_area: "); - out.append("'").append(this->suggested_area).append("'"); + append_quoted_string(out, this->suggested_area_ref_); out.append("\n"); #endif #ifdef USE_BLUETOOTH_PROXY out.append(" bluetooth_mac_address: "); - out.append("'").append(this->bluetooth_mac_address).append("'"); + append_quoted_string(out, this->bluetooth_mac_address_ref_); out.append("\n"); #endif @@ -770,7 +779,7 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesBinarySensorResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -779,11 +788,11 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); out.append(" is_status_binary_sensor: "); @@ -796,7 +805,7 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -844,7 +853,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesCoverResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -853,7 +862,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" assumed_state: "); @@ -869,7 +878,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); out.append(" disabled_by_default: "); @@ -878,7 +887,7 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -975,7 +984,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesFanResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -984,7 +993,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" supports_oscillation: "); @@ -1010,7 +1019,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -1020,7 +1029,7 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const { for (const auto &it : this->supported_preset_modes) { out.append(" supported_preset_modes: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -1059,7 +1068,7 @@ void FanStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" preset_mode: "); - out.append("'").append(this->preset_mode).append("'"); + append_quoted_string(out, this->preset_mode_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -1135,7 +1144,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesLightResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1144,7 +1153,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); for (const auto &it : this->supported_color_modes) { @@ -1165,7 +1174,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { for (const auto &it : this->effects) { out.append(" effects: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -1175,7 +1184,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -1254,7 +1263,7 @@ void LightStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" effect: "); - out.append("'").append(this->effect).append("'"); + append_quoted_string(out, this->effect_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -1404,7 +1413,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesSensorResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1413,17 +1422,17 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif out.append(" unit_of_measurement: "); - out.append("'").append(this->unit_of_measurement).append("'"); + append_quoted_string(out, this->unit_of_measurement_ref_); out.append("\n"); out.append(" accuracy_decimals: "); @@ -1436,7 +1445,7 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); out.append(" state_class: "); @@ -1492,7 +1501,7 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesSwitchResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1501,12 +1510,12 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -1523,7 +1532,7 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -1583,7 +1592,7 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesTextSensorResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1592,12 +1601,12 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -1610,7 +1619,7 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -1631,7 +1640,7 @@ void TextSensorStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" state: "); - out.append("'").append(this->state).append("'"); + append_quoted_string(out, this->state_ref_); out.append("\n"); out.append(" missing_state: "); @@ -1668,11 +1677,7 @@ void SubscribeLogsResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" message: "); - out.append(format_hex_pretty(this->message)); - out.append("\n"); - - out.append(" send_failed: "); - out.append(YESNO(this->send_failed)); + out.append(format_hex_pretty(this->message_ptr_, this->message_len_)); out.append("\n"); out.append("}"); } @@ -1681,7 +1686,7 @@ void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("NoiseEncryptionSetKeyRequest {\n"); out.append(" key: "); - out.append(format_hex_pretty(this->key)); + out.append(format_hex_pretty(reinterpret_cast(this->key.data()), this->key.size())); out.append("\n"); out.append("}"); } @@ -1701,11 +1706,11 @@ void HomeassistantServiceMap::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("HomeassistantServiceMap {\n"); out.append(" key: "); - out.append("'").append(this->key).append("'"); + append_quoted_string(out, this->key_ref_); out.append("\n"); out.append(" value: "); - out.append("'").append(this->value).append("'"); + append_quoted_string(out, this->value_ref_); out.append("\n"); out.append("}"); } @@ -1713,7 +1718,7 @@ void HomeassistantServiceResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("HomeassistantServiceResponse {\n"); out.append(" service: "); - out.append("'").append(this->service).append("'"); + append_quoted_string(out, this->service_ref_); out.append("\n"); for (const auto &it : this->data) { @@ -1746,11 +1751,11 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("SubscribeHomeAssistantStateResponse {\n"); out.append(" entity_id: "); - out.append("'").append(this->entity_id).append("'"); + append_quoted_string(out, this->entity_id_ref_); out.append("\n"); out.append(" attribute: "); - out.append("'").append(this->attribute).append("'"); + append_quoted_string(out, this->attribute_ref_); out.append("\n"); out.append(" once: "); @@ -1789,7 +1794,7 @@ void ListEntitiesServicesArgument::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesServicesArgument {\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" type: "); @@ -1801,7 +1806,7 @@ void ListEntitiesServicesResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesServicesResponse {\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" key: "); @@ -1864,7 +1869,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { for (const auto &it : this->string_array) { out.append(" string_array: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } out.append("}"); @@ -1890,7 +1895,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesCameraResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1899,7 +1904,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" disabled_by_default: "); @@ -1908,7 +1913,7 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -1934,7 +1939,7 @@ void CameraImageResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + out.append(format_hex_pretty(this->data_ptr_, this->data_len_)); out.append("\n"); out.append(" done: "); @@ -1968,7 +1973,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesClimateResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -1977,7 +1982,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); out.append(" supports_current_temperature: "); @@ -2027,7 +2032,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { for (const auto &it : this->supported_custom_fan_modes) { out.append(" supported_custom_fan_modes: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -2039,7 +2044,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { for (const auto &it : this->supported_custom_presets) { out.append(" supported_custom_presets: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -2049,7 +2054,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const { #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -2134,7 +2139,7 @@ void ClimateStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" custom_fan_mode: "); - out.append("'").append(this->custom_fan_mode).append("'"); + append_quoted_string(out, this->custom_fan_mode_ref_); out.append("\n"); out.append(" preset: "); @@ -2142,7 +2147,7 @@ void ClimateStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" custom_preset: "); - out.append("'").append(this->custom_preset).append("'"); + append_quoted_string(out, this->custom_preset_ref_); out.append("\n"); out.append(" current_humidity: "); @@ -2271,7 +2276,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesNumberResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2280,12 +2285,12 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -2313,7 +2318,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" unit_of_measurement: "); - out.append("'").append(this->unit_of_measurement).append("'"); + append_quoted_string(out, this->unit_of_measurement_ref_); out.append("\n"); out.append(" mode: "); @@ -2321,7 +2326,7 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -2387,7 +2392,7 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesSelectResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2396,18 +2401,18 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif for (const auto &it : this->options) { out.append(" options: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -2437,7 +2442,7 @@ void SelectStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" state: "); - out.append("'").append(this->state).append("'"); + append_quoted_string(out, this->state_ref_); out.append("\n"); out.append(" missing_state: "); @@ -2480,7 +2485,7 @@ void ListEntitiesSirenResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesSirenResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2489,12 +2494,12 @@ void ListEntitiesSirenResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -2504,7 +2509,7 @@ void ListEntitiesSirenResponse::dump_to(std::string &out) const { for (const auto &it : this->tones) { out.append(" tones: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -2607,7 +2612,7 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesLockResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2616,12 +2621,12 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -2646,7 +2651,7 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" code_format: "); - out.append("'").append(this->code_format).append("'"); + append_quoted_string(out, this->code_format_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -2714,7 +2719,7 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesButtonResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2723,12 +2728,12 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -2741,7 +2746,7 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -2776,7 +2781,7 @@ void MediaPlayerSupportedFormat::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("MediaPlayerSupportedFormat {\n"); out.append(" format: "); - out.append("'").append(this->format).append("'"); + append_quoted_string(out, this->format_ref_); out.append("\n"); out.append(" sample_rate: "); @@ -2803,7 +2808,7 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesMediaPlayerResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -2812,12 +2817,12 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -3143,7 +3148,7 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + out.append(format_hex_pretty(this->data_ptr_, this->data_len_)); out.append("\n"); out.append("}"); } @@ -3165,7 +3170,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + out.append(format_hex_pretty(reinterpret_cast(this->data.data()), this->data.size())); out.append("\n"); out.append("}"); } @@ -3197,7 +3202,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + out.append(format_hex_pretty(reinterpret_cast(this->data.data()), this->data.size())); out.append("\n"); out.append("}"); } @@ -3233,7 +3238,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + out.append(format_hex_pretty(this->data_ptr_, this->data_len_)); out.append("\n"); out.append("}"); } @@ -3427,7 +3432,7 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" conversation_id: "); - out.append("'").append(this->conversation_id).append("'"); + append_quoted_string(out, this->conversation_id_ref_); out.append("\n"); out.append(" flags: "); @@ -3440,7 +3445,7 @@ void VoiceAssistantRequest::dump_to(std::string &out) const { out.append("\n"); out.append(" wake_word_phrase: "); - out.append("'").append(this->wake_word_phrase).append("'"); + append_quoted_string(out, this->wake_word_phrase_ref_); out.append("\n"); out.append("}"); } @@ -3487,7 +3492,11 @@ void VoiceAssistantAudio::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantAudio {\n"); out.append(" data: "); - out.append(format_hex_pretty(this->data)); + if (this->data_ptr_ != nullptr) { + out.append(format_hex_pretty(this->data_ptr_, this->data_len_)); + } else { + out.append(format_hex_pretty(reinterpret_cast(this->data.data()), this->data.size())); + } out.append("\n"); out.append(" end: "); @@ -3557,16 +3566,16 @@ void VoiceAssistantWakeWord::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("VoiceAssistantWakeWord {\n"); out.append(" id: "); - out.append("'").append(this->id).append("'"); + append_quoted_string(out, this->id_ref_); out.append("\n"); out.append(" wake_word: "); - out.append("'").append(this->wake_word).append("'"); + append_quoted_string(out, this->wake_word_ref_); out.append("\n"); for (const auto &it : this->trained_languages) { out.append(" trained_languages: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } out.append("}"); @@ -3585,7 +3594,7 @@ void VoiceAssistantConfigurationResponse::dump_to(std::string &out) const { for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -3600,7 +3609,7 @@ void VoiceAssistantSetConfiguration::dump_to(std::string &out) const { out.append("VoiceAssistantSetConfiguration {\n"); for (const auto &it : this->active_wake_words) { out.append(" active_wake_words: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } out.append("}"); @@ -3611,7 +3620,7 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesAlarmControlPanelResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -3620,12 +3629,12 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -3711,7 +3720,7 @@ void ListEntitiesTextResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesTextResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -3720,12 +3729,12 @@ void ListEntitiesTextResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -3748,7 +3757,7 @@ void ListEntitiesTextResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" pattern: "); - out.append("'").append(this->pattern).append("'"); + append_quoted_string(out, this->pattern_ref_); out.append("\n"); out.append(" mode: "); @@ -3773,7 +3782,7 @@ void TextStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" state: "); - out.append("'").append(this->state).append("'"); + append_quoted_string(out, this->state_ref_); out.append("\n"); out.append(" missing_state: "); @@ -3816,7 +3825,7 @@ void ListEntitiesDateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesDateResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -3825,12 +3834,12 @@ void ListEntitiesDateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -3925,7 +3934,7 @@ void ListEntitiesTimeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesTimeResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -3934,12 +3943,12 @@ void ListEntitiesTimeResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -4034,7 +4043,7 @@ void ListEntitiesEventResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesEventResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -4043,12 +4052,12 @@ void ListEntitiesEventResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -4061,12 +4070,12 @@ void ListEntitiesEventResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); for (const auto &it : this->event_types) { out.append(" event_types: "); - out.append("'").append(it).append("'"); + append_quoted_string(out, StringRef(it)); out.append("\n"); } @@ -4088,7 +4097,7 @@ void EventResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" event_type: "); - out.append("'").append(this->event_type).append("'"); + append_quoted_string(out, this->event_type_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -4106,7 +4115,7 @@ void ListEntitiesValveResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesValveResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -4115,12 +4124,12 @@ void ListEntitiesValveResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -4133,7 +4142,7 @@ void ListEntitiesValveResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); out.append(" assumed_state: "); @@ -4219,7 +4228,7 @@ void ListEntitiesDateTimeResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesDateTimeResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -4228,12 +4237,12 @@ void ListEntitiesDateTimeResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -4308,7 +4317,7 @@ void ListEntitiesUpdateResponse::dump_to(std::string &out) const { __attribute__((unused)) char buffer[64]; out.append("ListEntitiesUpdateResponse {\n"); out.append(" object_id: "); - out.append("'").append(this->object_id).append("'"); + append_quoted_string(out, this->object_id_ref_); out.append("\n"); out.append(" key: "); @@ -4317,12 +4326,12 @@ void ListEntitiesUpdateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" name: "); - out.append("'").append(this->name).append("'"); + append_quoted_string(out, this->name_ref_); out.append("\n"); #ifdef USE_ENTITY_ICON out.append(" icon: "); - out.append("'").append(this->icon).append("'"); + append_quoted_string(out, this->icon_ref_); out.append("\n"); #endif @@ -4335,7 +4344,7 @@ void ListEntitiesUpdateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" device_class: "); - out.append("'").append(this->device_class).append("'"); + append_quoted_string(out, this->device_class_ref_); out.append("\n"); #ifdef USE_DEVICES @@ -4373,23 +4382,23 @@ void UpdateStateResponse::dump_to(std::string &out) const { out.append("\n"); out.append(" current_version: "); - out.append("'").append(this->current_version).append("'"); + append_quoted_string(out, this->current_version_ref_); out.append("\n"); out.append(" latest_version: "); - out.append("'").append(this->latest_version).append("'"); + append_quoted_string(out, this->latest_version_ref_); out.append("\n"); out.append(" title: "); - out.append("'").append(this->title).append("'"); + append_quoted_string(out, this->title_ref_); out.append("\n"); out.append(" release_summary: "); - out.append("'").append(this->release_summary).append("'"); + append_quoted_string(out, this->release_summary_ref_); out.append("\n"); out.append(" release_url: "); - out.append("'").append(this->release_url).append("'"); + append_quoted_string(out, this->release_url_ref_); out.append("\n"); #ifdef USE_DEVICES diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index a3c9bd80da..4ac2f75fb0 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -597,33 +597,28 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, } void APIServerConnection::on_hello_request(const HelloRequest &msg) { - HelloResponse ret = this->hello(msg); - if (!this->send_message(ret, HelloResponse::MESSAGE_TYPE)) { + if (!this->send_hello_response(msg)) { this->on_fatal_error(); } } void APIServerConnection::on_connect_request(const ConnectRequest &msg) { - ConnectResponse ret = this->connect(msg); - if (!this->send_message(ret, ConnectResponse::MESSAGE_TYPE)) { + if (!this->send_connect_response(msg)) { this->on_fatal_error(); } } void APIServerConnection::on_disconnect_request(const DisconnectRequest &msg) { - DisconnectResponse ret = this->disconnect(msg); - if (!this->send_message(ret, DisconnectResponse::MESSAGE_TYPE)) { + if (!this->send_disconnect_response(msg)) { this->on_fatal_error(); } } void APIServerConnection::on_ping_request(const PingRequest &msg) { - PingResponse ret = this->ping(msg); - if (!this->send_message(ret, PingResponse::MESSAGE_TYPE)) { + if (!this->send_ping_response(msg)) { this->on_fatal_error(); } } void APIServerConnection::on_device_info_request(const DeviceInfoRequest &msg) { if (this->check_connection_setup_()) { - DeviceInfoResponse ret = this->device_info(msg); - if (!this->send_message(ret, DeviceInfoResponse::MESSAGE_TYPE)) { + if (!this->send_device_info_response(msg)) { this->on_fatal_error(); } } @@ -656,8 +651,7 @@ void APIServerConnection::on_subscribe_home_assistant_states_request(const Subsc } void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) { if (this->check_connection_setup_()) { - GetTimeResponse ret = this->get_time(msg); - if (!this->send_message(ret, GetTimeResponse::MESSAGE_TYPE)) { + if (!this->send_get_time_response(msg)) { this->on_fatal_error(); } } @@ -672,8 +666,7 @@ void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest #ifdef USE_API_NOISE void APIServerConnection::on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg) { if (this->check_authenticated_()) { - NoiseEncryptionSetKeyResponse ret = this->noise_encryption_set_key(msg); - if (!this->send_message(ret, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE)) { + if (!this->send_noise_encryption_set_key_response(msg)) { this->on_fatal_error(); } } @@ -866,8 +859,7 @@ void APIServerConnection::on_bluetooth_gatt_notify_request(const BluetoothGATTNo void APIServerConnection::on_subscribe_bluetooth_connections_free_request( const SubscribeBluetoothConnectionsFreeRequest &msg) { if (this->check_authenticated_()) { - BluetoothConnectionsFreeResponse ret = this->subscribe_bluetooth_connections_free(msg); - if (!this->send_message(ret, BluetoothConnectionsFreeResponse::MESSAGE_TYPE)) { + if (!this->send_subscribe_bluetooth_connections_free_response(msg)) { this->on_fatal_error(); } } @@ -898,8 +890,7 @@ void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVo #ifdef USE_VOICE_ASSISTANT void APIServerConnection::on_voice_assistant_configuration_request(const VoiceAssistantConfigurationRequest &msg) { if (this->check_authenticated_()) { - VoiceAssistantConfigurationResponse ret = this->voice_assistant_get_configuration(msg); - if (!this->send_message(ret, VoiceAssistantConfigurationResponse::MESSAGE_TYPE)) { + if (!this->send_voice_assistant_get_configuration_response(msg)) { this->on_fatal_error(); } } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index f7076a28ca..f06ebdf9d5 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -207,22 +207,22 @@ class APIServerConnectionBase : public ProtoService { class APIServerConnection : public APIServerConnectionBase { public: - virtual HelloResponse hello(const HelloRequest &msg) = 0; - virtual ConnectResponse connect(const ConnectRequest &msg) = 0; - virtual DisconnectResponse disconnect(const DisconnectRequest &msg) = 0; - virtual PingResponse ping(const PingRequest &msg) = 0; - virtual DeviceInfoResponse device_info(const DeviceInfoRequest &msg) = 0; + virtual bool send_hello_response(const HelloRequest &msg) = 0; + virtual bool send_connect_response(const ConnectRequest &msg) = 0; + virtual bool send_disconnect_response(const DisconnectRequest &msg) = 0; + virtual bool send_ping_response(const PingRequest &msg) = 0; + virtual bool send_device_info_response(const DeviceInfoRequest &msg) = 0; virtual void list_entities(const ListEntitiesRequest &msg) = 0; virtual void subscribe_states(const SubscribeStatesRequest &msg) = 0; virtual void subscribe_logs(const SubscribeLogsRequest &msg) = 0; virtual void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) = 0; virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0; - virtual GetTimeResponse get_time(const GetTimeRequest &msg) = 0; + virtual bool send_get_time_response(const GetTimeRequest &msg) = 0; #ifdef USE_API_SERVICES virtual void execute_service(const ExecuteServiceRequest &msg) = 0; #endif #ifdef USE_API_NOISE - virtual NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) = 0; + virtual bool send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) = 0; #endif #ifdef USE_BUTTON virtual void button_command(const ButtonCommandRequest &msg) = 0; @@ -303,7 +303,7 @@ class APIServerConnection : public APIServerConnectionBase { virtual void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) = 0; #endif #ifdef USE_BLUETOOTH_PROXY - virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( + virtual bool send_subscribe_bluetooth_connections_free_response( const SubscribeBluetoothConnectionsFreeRequest &msg) = 0; #endif #ifdef USE_BLUETOOTH_PROXY @@ -316,8 +316,7 @@ class APIServerConnection : public APIServerConnectionBase { virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; #endif #ifdef USE_VOICE_ASSISTANT - virtual VoiceAssistantConfigurationResponse voice_assistant_get_configuration( - const VoiceAssistantConfigurationRequest &msg) = 0; + virtual bool send_voice_assistant_get_configuration_response(const VoiceAssistantConfigurationRequest &msg) = 0; #endif #ifdef USE_VOICE_ASSISTANT virtual void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) = 0; diff --git a/esphome/components/api/custom_api_device.h b/esphome/components/api/custom_api_device.h index 35329c4a5e..6375dbfb9f 100644 --- a/esphome/components/api/custom_api_device.h +++ b/esphome/components/api/custom_api_device.h @@ -148,7 +148,7 @@ class CustomAPIDevice { */ void call_homeassistant_service(const std::string &service_name) { HomeassistantServiceResponse resp; - resp.service = service_name; + resp.set_service(StringRef(service_name)); global_api_server->send_homeassistant_service_call(resp); } @@ -168,12 +168,12 @@ class CustomAPIDevice { */ void call_homeassistant_service(const std::string &service_name, const std::map &data) { HomeassistantServiceResponse resp; - resp.service = service_name; + resp.set_service(StringRef(service_name)); for (auto &it : data) { - HomeassistantServiceMap kv; - kv.key = it.first; - kv.value = it.second; - resp.data.push_back(kv); + resp.data.emplace_back(); + auto &kv = resp.data.back(); + kv.set_key(StringRef(it.first)); + kv.set_value(StringRef(it.second)); } global_api_server->send_homeassistant_service_call(resp); } @@ -190,7 +190,7 @@ class CustomAPIDevice { */ void fire_homeassistant_event(const std::string &event_name) { HomeassistantServiceResponse resp; - resp.service = event_name; + resp.set_service(StringRef(event_name)); resp.is_event = true; global_api_server->send_homeassistant_service_call(resp); } @@ -210,13 +210,13 @@ class CustomAPIDevice { */ void fire_homeassistant_event(const std::string &service_name, const std::map &data) { HomeassistantServiceResponse resp; - resp.service = service_name; + resp.set_service(StringRef(service_name)); resp.is_event = true; for (auto &it : data) { - HomeassistantServiceMap kv; - kv.key = it.first; - kv.value = it.second; - resp.data.push_back(kv); + resp.data.emplace_back(); + auto &kv = resp.data.back(); + kv.set_key(StringRef(it.first)); + kv.set_value(StringRef(it.second)); } global_api_server->send_homeassistant_service_call(resp); } diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index f765f1f806..4980c0224c 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -59,25 +59,29 @@ template class HomeAssistantServiceCallAction : public Actionservice_.value(x...); + std::string service_value = this->service_.value(x...); + resp.set_service(StringRef(service_value)); resp.is_event = this->is_event_; for (auto &it : this->data_) { - HomeassistantServiceMap kv; - kv.key = it.key; - kv.value = it.value.value(x...); - resp.data.push_back(kv); + resp.data.emplace_back(); + auto &kv = resp.data.back(); + kv.set_key(StringRef(it.key)); + std::string value = it.value.value(x...); + kv.set_value(StringRef(value)); } for (auto &it : this->data_template_) { - HomeassistantServiceMap kv; - kv.key = it.key; - kv.value = it.value.value(x...); - resp.data_template.push_back(kv); + resp.data_template.emplace_back(); + auto &kv = resp.data_template.back(); + kv.set_key(StringRef(it.key)); + std::string value = it.value.value(x...); + kv.set_value(StringRef(value)); } for (auto &it : this->variables_) { - HomeassistantServiceMap kv; - kv.key = it.key; - kv.value = it.value.value(x...); - resp.variables.push_back(kv); + resp.variables.emplace_back(); + auto &kv = resp.variables.back(); + kv.set_key(StringRef(it.key)); + std::string value = it.value.value(x...); + kv.set_value(StringRef(value)); } this->parent_->send_homeassistant_service_call(resp); } diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index a2c31100bf..3e59ee1541 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -3,8 +3,10 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "esphome/core/string_ref.h" #include +#include #include #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE @@ -14,6 +16,37 @@ namespace esphome { namespace api { +/* + * StringRef Ownership Model for API Protocol Messages + * =================================================== + * + * StringRef is used for zero-copy string handling in outgoing (SOURCE_SERVER) messages. + * It holds a pointer and length to existing string data without copying. + * + * CRITICAL: The referenced string data MUST remain valid until message encoding completes. + * + * Safe StringRef Patterns: + * 1. String literals: StringRef("literal") - Always safe (static storage duration) + * 2. Member variables: StringRef(this->member_string_) - Safe if object outlives encoding + * 3. Global/static strings: StringRef(GLOBAL_CONSTANT) - Always safe + * 4. Local variables: Safe ONLY if encoding happens before function returns: + * std::string temp = compute_value(); + * msg.set_field(StringRef(temp)); + * return this->send_message(msg); // temp is valid during encoding + * + * Unsafe Patterns (WILL cause crashes/corruption): + * 1. Temporaries: msg.set_field(StringRef(obj.get_string())) // get_string() returns by value + * 2. Optional values: msg.set_field(StringRef(optional.value())) // value() returns a copy + * 3. Concatenation: msg.set_field(StringRef(str1 + str2)) // Result is temporary + * + * For unsafe patterns, store in a local variable first: + * std::string temp = optional.value(); // or get_string() or str1 + str2 + * msg.set_field(StringRef(temp)); + * + * The send_*_response pattern ensures proper lifetime management by encoding + * within the same function scope where temporaries are created. + */ + /// Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit class ProtoVarInt { public: @@ -206,12 +239,20 @@ class ProtoWriteBuffer { this->encode_field_raw(field_id, 2); // type 2: Length-delimited string this->encode_varint_raw(len); - auto *data = reinterpret_cast(string); - this->buffer_->insert(this->buffer_->end(), data, data + len); + + // Using resize + memcpy instead of insert provides significant performance improvement: + // ~10-11x faster for 16-32 byte strings, ~3x faster for 64-byte strings + // as it avoids iterator checks and potential element moves that insert performs + size_t old_size = this->buffer_->size(); + this->buffer_->resize(old_size + len); + std::memcpy(this->buffer_->data() + old_size, string, len); } void encode_string(uint32_t field_id, const std::string &value, bool force = false) { this->encode_string(field_id, value.data(), value.size(), force); } + void encode_string(uint32_t field_id, const StringRef &ref, bool force = false) { + this->encode_string(field_id, ref.c_str(), ref.size(), force); + } void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) { this->encode_string(field_id, reinterpret_cast(data), len, force); } @@ -527,25 +568,6 @@ class ProtoSize { total_size += field_id_size + 1; } - /** - * @brief Calculates and adds the size of a fixed field to the total message size - * - * Fixed fields always take exactly N bytes (4 for fixed32/float, 8 for fixed64/double). - * - * @tparam NumBytes The number of bytes for this fixed field (4 or 8) - * @param is_nonzero Whether the value is non-zero - */ - template - static inline void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero) { - // Skip calculation if value is zero - if (!is_nonzero) { - return; // No need to update total_size - } - - // Fixed fields always take exactly NumBytes - total_size += field_id_size + NumBytes; - } - /** * @brief Calculates and adds the size of a float field to the total message size */ @@ -682,17 +704,16 @@ class ProtoSize { // sint64 type is not supported by ESPHome API to reduce overhead on embedded systems /** - * @brief Calculates and adds the size of a string/bytes field to the total message size + * @brief Calculates and adds the size of a string field using length */ - static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str) { + static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, size_t len) { // Skip calculation if string is empty - if (str.empty()) { + if (len == 0) { return; // No need to update total_size } - // Calculate and directly add to total_size - const uint32_t str_size = static_cast(str.size()); - total_size += field_id_size + varint(str_size) + str_size; + // Field ID + length varint + string bytes + total_size += field_id_size + varint(static_cast(len)) + static_cast(len); } /** @@ -704,6 +725,19 @@ class ProtoSize { total_size += field_id_size + varint(str_size) + str_size; } + /** + * @brief Calculates and adds the size of a bytes field to the total message size + */ + static inline void add_bytes_field(uint32_t &total_size, uint32_t field_id_size, size_t len) { + // Skip calculation if bytes is empty + if (len == 0) { + return; // No need to update total_size + } + + // Field ID + length varint + data bytes + total_size += field_id_size + varint(static_cast(len)) + static_cast(len); + } + /** * @brief Calculates and adds the size of a nested message field to the total message size * diff --git a/esphome/components/api/user_services.h b/esphome/components/api/user_services.h index 1420a15ff9..deec636cae 100644 --- a/esphome/components/api/user_services.h +++ b/esphome/components/api/user_services.h @@ -33,14 +33,14 @@ template class UserServiceBase : public UserServiceDescriptor { ListEntitiesServicesResponse encode_list_service_response() override { ListEntitiesServicesResponse msg; - msg.name = this->name_; + msg.set_name(StringRef(this->name_)); msg.key = this->key_; std::array arg_types = {to_service_arg_type()...}; for (int i = 0; i < sizeof...(Ts); i++) { - ListEntitiesServicesArgument arg; + msg.args.emplace_back(); + auto &arg = msg.args.back(); arg.type = arg_types[i]; - arg.name = this->arg_names_[i]; - msg.args.push_back(arg); + arg.set_name(StringRef(this->arg_names_[i])); } return msg; } diff --git a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp index 85380fa486..616dba891a 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_connection.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_connection.cpp @@ -13,16 +13,16 @@ namespace bluetooth_proxy { static const char *const TAG = "bluetooth_proxy.connection"; -static std::vector get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) { +static void fill_128bit_uuid_array(std::array &out, esp_bt_uuid_t uuid_source) { esp_bt_uuid_t uuid = espbt::ESPBTUUID::from_uuid(uuid_source).as_128bit().get_uuid(); - return std::vector{((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) | - ((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) | - ((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) | - ((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]), - ((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) | - ((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) | - ((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) | - ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0])}; + out[0] = ((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) | + ((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) | + ((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) | + ((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]); + out[1] = ((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) | + ((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) | + ((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) | + ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0]); } void BluetoothConnection::dump_config() { @@ -95,9 +95,8 @@ void BluetoothConnection::send_service_for_discovery_() { api::BluetoothGATTGetServicesResponse resp; resp.address = this->address_; - resp.services.emplace_back(); - auto &service_resp = resp.services.back(); - service_resp.uuid = get_128bit_uuid_vec(service_result.uuid); + auto &service_resp = resp.services[0]; + fill_128bit_uuid_array(service_resp.uuid, service_result.uuid); service_resp.handle = service_result.start_handle; // Get the number of characteristics directly with one call @@ -136,7 +135,7 @@ void BluetoothConnection::send_service_for_discovery_() { service_resp.characteristics.emplace_back(); auto &characteristic_resp = service_resp.characteristics.back(); - characteristic_resp.uuid = get_128bit_uuid_vec(char_result.uuid); + fill_128bit_uuid_array(characteristic_resp.uuid, char_result.uuid); characteristic_resp.handle = char_result.char_handle; characteristic_resp.properties = char_result.properties; char_offset++; @@ -176,7 +175,7 @@ void BluetoothConnection::send_service_for_discovery_() { characteristic_resp.descriptors.emplace_back(); auto &descriptor_resp = characteristic_resp.descriptors.back(); - descriptor_resp.uuid = get_128bit_uuid_vec(desc_result.uuid); + fill_128bit_uuid_array(descriptor_resp.uuid, desc_result.uuid); descriptor_resp.handle = desc_result.handle; desc_offset++; } @@ -234,9 +233,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTReadResponse resp; resp.address = this->address_; resp.handle = param->read.handle; - resp.data.reserve(param->read.value_len); - // Use bulk insert instead of individual push_backs - resp.data.insert(resp.data.end(), param->read.value, param->read.value + param->read.value_len); + resp.set_data(param->read.value, param->read.value_len); this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTReadResponse::MESSAGE_TYPE); break; } @@ -287,9 +284,7 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga api::BluetoothGATTNotifyDataResponse resp; resp.address = this->address_; resp.handle = param->notify.handle; - resp.data.reserve(param->notify.value_len); - // Use bulk insert instead of individual push_backs - resp.data.insert(resp.data.end(), param->notify.value, param->notify.value + param->notify.value_len); + resp.set_data(param->notify.value, param->notify.value_len); this->proxy_->get_api_connection()->send_message(resp, api::BluetoothGATTNotifyDataResponse::MESSAGE_TYPE); break; } diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index 8ee463a59a..330dc4dd9c 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg from esphome.components import esp32, i2c import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET +from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET, Framework CODEOWNERS = ["@trvrnrth"] DEPENDENCIES = ["i2c"] @@ -56,7 +56,15 @@ CONFIG_SCHEMA = cv.All( ): cv.positive_time_period_minutes, } ).extend(i2c.i2c_device_schema(0x76)), - cv.only_with_arduino, + cv.only_with_framework( + frameworks=Framework.ARDUINO, + suggestions={ + Framework.ESP_IDF: ( + "bme68x_bsec2_i2c", + "sensor/bme68x_bsec2", + ) + }, + ), cv.Any( cv.only_on_esp8266, cv.All( diff --git a/esphome/components/esp32_ble_tracker/__init__.py b/esphome/components/esp32_ble_tracker/__init__.py index 68f4657515..046f3f679f 100644 --- a/esphome/components/esp32_ble_tracker/__init__.py +++ b/esphome/components/esp32_ble_tracker/__init__.py @@ -30,7 +30,7 @@ from esphome.const import ( CONF_SERVICE_UUID, CONF_TRIGGER_ID, ) -from esphome.core import CORE +from esphome.core import CORE, coroutine_with_priority from esphome.enum import StrEnum from esphome.types import ConfigType @@ -365,14 +365,22 @@ async def to_code(config): cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts cg.add_define("USE_ESP32_BLE_CLIENT") - # Add feature-specific defines based on what's needed - if BLEFeatures.ESP_BT_DEVICE in _required_features: - cg.add_define("USE_ESP32_BLE_DEVICE") + CORE.add_job(_add_ble_features) if config.get(CONF_SOFTWARE_COEXISTENCE): cg.add_define("USE_ESP32_BLE_SOFTWARE_COEXISTENCE") +# This needs to be run as a job with very low priority so that all components have +# chance to call register_ble_tracker and register_client before the list is checked +# and added to the global defines list. +@coroutine_with_priority(-1000) +async def _add_ble_features(): + # Add feature-specific defines based on what's needed + if BLEFeatures.ESP_BT_DEVICE in _required_features: + cg.add_define("USE_ESP32_BLE_DEVICE") + + ESP32_BLE_START_SCAN_ACTION_SCHEMA = cv.Schema( { cv.GenerateID(): cv.use_id(ESP32BLETracker), diff --git a/esphome/components/esp32_touch/esp32_touch_v1.cpp b/esphome/components/esp32_touch/esp32_touch_v1.cpp index c3d43c6bbf..629dc8e793 100644 --- a/esphome/components/esp32_touch/esp32_touch_v1.cpp +++ b/esphome/components/esp32_touch/esp32_touch_v1.cpp @@ -16,6 +16,8 @@ namespace esp32_touch { static const char *const TAG = "esp32_touch"; +static const uint32_t SETUP_MODE_THRESHOLD = 0xFFFF; + void ESP32TouchComponent::setup() { // Create queue for touch events // Queue size calculation: children * 4 allows for burst scenarios where ISR @@ -44,7 +46,11 @@ void ESP32TouchComponent::setup() { // Configure each touch pad for (auto *child : this->children_) { - touch_pad_config(child->get_touch_pad(), child->get_threshold()); + if (this->setup_mode_) { + touch_pad_config(child->get_touch_pad(), SETUP_MODE_THRESHOLD); + } else { + touch_pad_config(child->get_touch_pad(), child->get_threshold()); + } } // Register ISR handler @@ -114,8 +120,8 @@ void ESP32TouchComponent::loop() { child->publish_state(new_state); // Original ESP32: ISR only fires when touched, release is detected by timeout // Note: ESP32 v1 uses inverted logic - touched when value < threshold - ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 " < threshold: %" PRIu32 ")", - child->get_name().c_str(), event.value, child->get_threshold()); + ESP_LOGV(TAG, "Touch Pad '%s' state: %s (value: %" PRIu32 " < threshold: %" PRIu32 ")", + child->get_name().c_str(), ONOFF(new_state), event.value, child->get_threshold()); } break; // Exit inner loop after processing matching pad } @@ -188,11 +194,6 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { // as any pad remains touched. This allows us to detect both new touches and // continued touches, but releases must be detected by timeout in the main loop. - // IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2! - // ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE - // Therefore: touched = (value < threshold) - // This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold) - // Process all configured pads to check their current state // Note: ESP32 v1 doesn't tell us which specific pad triggered the interrupt, // so we must scan all configured pads to find which ones were touched @@ -211,11 +212,16 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) { } // Skip pads that aren’t in the trigger mask - bool is_touched = (mask >> pad) & 1; - if (!is_touched) { + if (((mask >> pad) & 1) == 0) { continue; } + // IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2! + // ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE + // Therefore: touched = (value < threshold) + // This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold) + bool is_touched = value < child->get_threshold(); + // Always send the current state - the main loop will filter for changes // We send both touched and untouched states because the ISR doesn't // track previous state (to keep ISR fast and simple) diff --git a/esphome/components/fastled_clockless/light.py b/esphome/components/fastled_clockless/light.py index 49a6d390be..aa2172bf88 100644 --- a/esphome/components/fastled_clockless/light.py +++ b/esphome/components/fastled_clockless/light.py @@ -2,7 +2,13 @@ from esphome import pins import esphome.codegen as cg from esphome.components import fastled_base import esphome.config_validation as cv -from esphome.const import CONF_CHIPSET, CONF_NUM_LEDS, CONF_PIN, CONF_RGB_ORDER +from esphome.const import ( + CONF_CHIPSET, + CONF_NUM_LEDS, + CONF_PIN, + CONF_RGB_ORDER, + Framework, +) AUTO_LOAD = ["fastled_base"] @@ -48,13 +54,22 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number, } ), - _validate, + cv.only_with_framework( + frameworks=Framework.ARDUINO, + suggestions={ + Framework.ESP_IDF: ( + "esp32_rmt_led_strip", + "light/esp32_rmt_led_strip", + ) + }, + ), cv.require_framework_version( esp8266_arduino=cv.Version(2, 7, 4), esp32_arduino=cv.Version(99, 0, 0), max_version=True, extra_message="Please see note on documentation for FastLED", ), + _validate, ) diff --git a/esphome/components/fastled_spi/light.py b/esphome/components/fastled_spi/light.py index ac30721eb4..81d8c3b32a 100644 --- a/esphome/components/fastled_spi/light.py +++ b/esphome/components/fastled_spi/light.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_DATA_RATE, CONF_NUM_LEDS, CONF_RGB_ORDER, + Framework, ) AUTO_LOAD = ["fastled_base"] @@ -33,6 +34,15 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DATA_RATE): cv.frequency, } ), + cv.only_with_framework( + frameworks=Framework.ARDUINO, + suggestions={ + Framework.ESP_IDF: ( + "spi_led_strip", + "light/spi_led_strip", + ) + }, + ), cv.require_framework_version( esp8266_arduino=cv.Version(2, 7, 4), esp32_arduino=cv.Version(99, 0, 0), diff --git a/esphome/components/homeassistant/number/homeassistant_number.cpp b/esphome/components/homeassistant/number/homeassistant_number.cpp index a7f71c3244..ffb352c969 100644 --- a/esphome/components/homeassistant/number/homeassistant_number.cpp +++ b/esphome/components/homeassistant/number/homeassistant_number.cpp @@ -83,18 +83,24 @@ void HomeassistantNumber::control(float value) { this->publish_state(value); + static constexpr auto SERVICE_NAME = StringRef::from_lit("number.set_value"); + static constexpr auto ENTITY_ID_KEY = StringRef::from_lit("entity_id"); + static constexpr auto VALUE_KEY = StringRef::from_lit("value"); + api::HomeassistantServiceResponse resp; - resp.service = "number.set_value"; + resp.set_service(SERVICE_NAME); - api::HomeassistantServiceMap entity_id; - entity_id.key = "entity_id"; - entity_id.value = this->entity_id_; - resp.data.push_back(entity_id); + resp.data.emplace_back(); + auto &entity_id = resp.data.back(); + entity_id.set_key(ENTITY_ID_KEY); + entity_id.set_value(StringRef(this->entity_id_)); - api::HomeassistantServiceMap entity_value; - entity_value.key = "value"; - entity_value.value = to_string(value); - resp.data.push_back(entity_value); + resp.data.emplace_back(); + auto &entity_value = resp.data.back(); + entity_value.set_key(VALUE_KEY); + // to_string() returns a temporary - must store it to avoid dangling reference + std::string value_str = to_string(value); + entity_value.set_value(StringRef(value_str)); api::global_api_server->send_homeassistant_service_call(resp); } diff --git a/esphome/components/homeassistant/switch/homeassistant_switch.cpp b/esphome/components/homeassistant/switch/homeassistant_switch.cpp index 0451c95069..0fe609bf43 100644 --- a/esphome/components/homeassistant/switch/homeassistant_switch.cpp +++ b/esphome/components/homeassistant/switch/homeassistant_switch.cpp @@ -40,17 +40,21 @@ void HomeassistantSwitch::write_state(bool state) { return; } + static constexpr auto SERVICE_ON = StringRef::from_lit("homeassistant.turn_on"); + static constexpr auto SERVICE_OFF = StringRef::from_lit("homeassistant.turn_off"); + static constexpr auto ENTITY_ID_KEY = StringRef::from_lit("entity_id"); + api::HomeassistantServiceResponse resp; if (state) { - resp.service = "homeassistant.turn_on"; + resp.set_service(SERVICE_ON); } else { - resp.service = "homeassistant.turn_off"; + resp.set_service(SERVICE_OFF); } - api::HomeassistantServiceMap entity_id_kv; - entity_id_kv.key = "entity_id"; - entity_id_kv.value = this->entity_id_; - resp.data.push_back(entity_id_kv); + resp.data.emplace_back(); + auto &entity_id_kv = resp.data.back(); + entity_id_kv.set_key(ENTITY_ID_KEY); + entity_id_kv.set_value(StringRef(this->entity_id_)); api::global_api_server->send_homeassistant_service_call(resp); } diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index 3cd1bfd357..c63790e60b 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -15,6 +15,7 @@ from esphome.const import ( CONF_PIN, CONF_TYPE, CONF_VARIANT, + Framework, ) from esphome.core import CORE @@ -162,7 +163,15 @@ def _validate_method(value): CONFIG_SCHEMA = cv.All( - cv.only_with_arduino, + cv.only_with_framework( + frameworks=Framework.ARDUINO, + suggestions={ + Framework.ESP_IDF: ( + "esp32_rmt_led_strip", + "light/esp32_rmt_led_strip", + ) + }, + ), cv.require_framework_version( esp8266_arduino=cv.Version(2, 4, 0), esp32_arduino=cv.Version(0, 0, 0), diff --git a/esphome/components/nrf52/__init__.py b/esphome/components/nrf52/__init__.py index c23298e38f..870c51066c 100644 --- a/esphome/components/nrf52/__init__.py +++ b/esphome/components/nrf52/__init__.py @@ -23,6 +23,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_NRF52, + CoreModel, ) from esphome.core import CORE, EsphomeError, coroutine_with_priority from esphome.storage_json import StorageJSON @@ -108,6 +109,8 @@ async def to_code(config: ConfigType) -> None: cg.add_build_flag("-DUSE_NRF52") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "NRF52") + # nRF52 processors are single-core + cg.add_define(CoreModel.SINGLE) cg.add_platformio_option(CONF_FRAMEWORK, CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK]) cg.add_platformio_option( "platform", diff --git a/esphome/components/text/text_traits.h b/esphome/components/text/text_traits.h index 952afa70c7..ceaba2dead 100644 --- a/esphome/components/text/text_traits.h +++ b/esphome/components/text/text_traits.h @@ -3,6 +3,7 @@ #include #include "esphome/core/helpers.h" +#include "esphome/core/string_ref.h" namespace esphome { namespace text { @@ -23,6 +24,7 @@ class TextTraits { // Set/get the pattern. void set_pattern(std::string pattern) { this->pattern_ = std::move(pattern); } std::string get_pattern() const { return this->pattern_; } + StringRef get_pattern_ref() const { return StringRef(this->pattern_); } // Set/get the frontend mode. void set_mode(TextMode mode) { this->mode_ = mode; } diff --git a/esphome/components/tuya/fan/__init__.py b/esphome/components/tuya/fan/__init__.py index c732bdaf31..de95888b6b 100644 --- a/esphome/components/tuya/fan/__init__.py +++ b/esphome/components/tuya/fan/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg from esphome.components import fan import esphome.config_validation as cv -from esphome.const import CONF_OUTPUT_ID, CONF_SPEED_COUNT, CONF_SWITCH_DATAPOINT +from esphome.const import CONF_ID, CONF_SPEED_COUNT, CONF_SWITCH_DATAPOINT from .. import CONF_TUYA_ID, Tuya, tuya_ns @@ -14,9 +14,9 @@ CONF_DIRECTION_DATAPOINT = "direction_datapoint" TuyaFan = tuya_ns.class_("TuyaFan", cg.Component, fan.Fan) CONFIG_SCHEMA = cv.All( - fan.FAN_SCHEMA.extend( + fan.fan_schema(TuyaFan) + .extend( { - cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(TuyaFan), cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya), cv.Optional(CONF_OSCILLATION_DATAPOINT): cv.uint8_t, cv.Optional(CONF_SPEED_DATAPOINT): cv.uint8_t, @@ -24,7 +24,8 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_DIRECTION_DATAPOINT): cv.uint8_t, cv.Optional(CONF_SPEED_COUNT, default=3): cv.int_range(min=1, max=256), } - ).extend(cv.COMPONENT_SCHEMA), + ) + .extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_SPEED_DATAPOINT, CONF_SWITCH_DATAPOINT), ) @@ -32,7 +33,7 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): parent = await cg.get_variable(config[CONF_TUYA_ID]) - var = cg.new_Pvariable(config[CONF_OUTPUT_ID], parent, config[CONF_SPEED_COUNT]) + var = cg.new_Pvariable(config[CONF_ID], parent, config[CONF_SPEED_COUNT]) await cg.register_component(var, config) await fan.register_fan(var, config) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 3c69dafa43..743c90e700 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -238,10 +238,10 @@ void VoiceAssistant::loop() { api::VoiceAssistantRequest msg; msg.start = true; - msg.conversation_id = this->conversation_id_; + msg.set_conversation_id(StringRef(this->conversation_id_)); msg.flags = flags; msg.audio_settings = audio_settings; - msg.wake_word_phrase = this->wake_word_; + msg.set_wake_word_phrase(StringRef(this->wake_word_)); this->wake_word_ = ""; // Reset media player state tracking @@ -273,7 +273,7 @@ void VoiceAssistant::loop() { size_t read_bytes = this->ring_buffer_->read((void *) this->send_buffer_, SEND_BUFFER_SIZE, 0); if (this->audio_mode_ == AUDIO_MODE_API) { api::VoiceAssistantAudio msg; - msg.data.assign((char *) this->send_buffer_, read_bytes); + msg.set_data(this->send_buffer_, read_bytes); this->api_client_->send_message(msg, api::VoiceAssistantAudio::MESSAGE_TYPE); } else { if (!this->udp_socket_running_) { diff --git a/esphome/config_validation.py b/esphome/config_validation.py index b1691fa43e..756464b563 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -73,6 +73,7 @@ from esphome.const import ( TYPE_GIT, TYPE_LOCAL, VALID_SUBSTITUTIONS_CHARACTERS, + Framework, __version__ as ESPHOME_VERSION, ) from esphome.core import ( @@ -282,6 +283,38 @@ class FinalExternalInvalid(Invalid): """Represents an invalid value in the final validation phase where the path should not be prepended.""" +@dataclass(frozen=True, order=True) +class Version: + major: int + minor: int + patch: int + extra: str = "" + + def __str__(self): + return f"{self.major}.{self.minor}.{self.patch}" + + @classmethod + def parse(cls, value: str) -> Version: + match = re.match(r"^(\d+).(\d+).(\d+)-?(\w*)$", value) + if match is None: + raise ValueError(f"Not a valid version number {value}") + major = int(match[1]) + minor = int(match[2]) + patch = int(match[3]) + extra = match[4] or "" + return Version(major=major, minor=minor, patch=patch, extra=extra) + + @property + def is_beta(self) -> bool: + """Check if this version is a beta version.""" + return self.extra.startswith("b") + + @property + def is_dev(self) -> bool: + """Check if this version is a development version.""" + return self.extra.startswith("dev") + + def check_not_templatable(value): if isinstance(value, Lambda): raise Invalid("This option is not templatable!") @@ -619,16 +652,35 @@ def only_on(platforms): return validator_ -def only_with_framework(frameworks): +def only_with_framework( + frameworks: Framework | str | list[Framework | str], suggestions=None +): """Validate that this option can only be specified on the given frameworks.""" if not isinstance(frameworks, list): frameworks = [frameworks] + frameworks = [Framework(framework) for framework in frameworks] + + if suggestions is None: + suggestions = {} + + version = Version.parse(ESPHOME_VERSION) + if version.is_beta: + docs_format = "https://beta.esphome.io/components/{path}" + elif version.is_dev: + docs_format = "https://next.esphome.io/components/{path}" + else: + docs_format = "https://esphome.io/components/{path}" + def validator_(obj): if CORE.target_framework not in frameworks: - raise Invalid( - f"This feature is only available with frameworks {frameworks}" - ) + err_str = f"This feature is only available with framework(s) {', '.join([framework.value for framework in frameworks])}" + if suggestion := suggestions.get(CORE.target_framework, None): + (component, docs_path) = suggestion + err_str += f"\nPlease use '{component}'" + if docs_path: + err_str += f": {docs_format.format(path=docs_path)}" + raise Invalid(err_str) return obj return validator_ @@ -637,8 +689,8 @@ def only_with_framework(frameworks): only_on_esp32 = only_on(PLATFORM_ESP32) only_on_esp8266 = only_on(PLATFORM_ESP8266) only_on_rp2040 = only_on(PLATFORM_RP2040) -only_with_arduino = only_with_framework("arduino") -only_with_esp_idf = only_with_framework("esp-idf") +only_with_arduino = only_with_framework(Framework.ARDUINO) +only_with_esp_idf = only_with_framework(Framework.ESP_IDF) # Adapted from: @@ -1966,26 +2018,6 @@ def source_refresh(value: str): return positive_time_period_seconds(value) -@dataclass(frozen=True, order=True) -class Version: - major: int - minor: int - patch: int - - def __str__(self): - return f"{self.major}.{self.minor}.{self.patch}" - - @classmethod - def parse(cls, value: str) -> Version: - match = re.match(r"^(\d+).(\d+).(\d+)-?\w*$", value) - if match is None: - raise ValueError(f"Not a valid version number {value}") - major = int(match[1]) - minor = int(match[2]) - patch = int(match[3]) - return Version(major=major, minor=minor, patch=patch) - - def version_number(value): value = string_strict(value) try: diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 748c8f2237..873f342277 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -71,8 +71,11 @@ void Application::setup() { do { uint8_t new_app_state = STATUS_LED_WARNING; - this->scheduler.call(millis()); - this->feed_wdt(); + uint32_t now = millis(); + + // Process pending loop enables to handle GPIO interrupts during setup + this->before_loop_tasks_(now); + for (uint32_t j = 0; j <= i; j++) { // Update loop_component_start_time_ right before calling each component this->loop_component_start_time_ = millis(); @@ -81,6 +84,8 @@ void Application::setup() { this->app_state_ |= new_app_state; this->feed_wdt(); } + + this->after_loop_tasks_(); this->app_state_ = new_app_state; yield(); } while (!component->can_proceed()); @@ -100,27 +105,7 @@ void Application::loop() { // Get the initial loop time at the start uint32_t last_op_end_time = millis(); - this->scheduler.call(last_op_end_time); - - // Feed WDT with time - this->feed_wdt(last_op_end_time); - - // Process any pending enable_loop requests from ISRs - // This must be done before marking in_loop_ = true to avoid race conditions - if (this->has_pending_enable_loop_requests_) { - // Clear flag BEFORE processing to avoid race condition - // If ISR sets it during processing, we'll catch it next loop iteration - // This is safe because: - // 1. Each component has its own pending_enable_loop_ flag that we check - // 2. If we can't process a component (wrong state), enable_pending_loops_() - // will set this flag back to true - // 3. Any new ISR requests during processing will set the flag again - this->has_pending_enable_loop_requests_ = false; - this->enable_pending_loops_(); - } - - // Mark that we're in the loop for safe reentrant modifications - this->in_loop_ = true; + this->before_loop_tasks_(last_op_end_time); for (this->current_loop_index_ = 0; this->current_loop_index_ < this->looping_components_active_end_; this->current_loop_index_++) { @@ -141,7 +126,7 @@ void Application::loop() { this->feed_wdt(last_op_end_time); } - this->in_loop_ = false; + this->after_loop_tasks_(); this->app_state_ = new_app_state; #ifdef USE_RUNTIME_STATS @@ -411,6 +396,36 @@ void Application::enable_pending_loops_() { } } +void Application::before_loop_tasks_(uint32_t loop_start_time) { + // Process scheduled tasks + this->scheduler.call(loop_start_time); + + // Feed the watchdog timer + this->feed_wdt(loop_start_time); + + // Process any pending enable_loop requests from ISRs + // This must be done before marking in_loop_ = true to avoid race conditions + if (this->has_pending_enable_loop_requests_) { + // Clear flag BEFORE processing to avoid race condition + // If ISR sets it during processing, we'll catch it next loop iteration + // This is safe because: + // 1. Each component has its own pending_enable_loop_ flag that we check + // 2. If we can't process a component (wrong state), enable_pending_loops_() + // will set this flag back to true + // 3. Any new ISR requests during processing will set the flag again + this->has_pending_enable_loop_requests_ = false; + this->enable_pending_loops_(); + } + + // Mark that we're in the loop for safe reentrant modifications + this->in_loop_ = true; +} + +void Application::after_loop_tasks_() { + // Clear the in_loop_ flag to indicate we're done processing components + this->in_loop_ = false; +} + #ifdef USE_SOCKET_SELECT_SUPPORT bool Application::register_socket_fd(int fd) { // WARNING: This function is NOT thread-safe and must only be called from the main loop diff --git a/esphome/core/application.h b/esphome/core/application.h index 75b9769ca3..a83789837f 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -512,6 +512,8 @@ class Application { void enable_component_loop_(Component *component); void enable_pending_loops_(); void activate_looping_component_(uint16_t index); + void before_loop_tasks_(uint32_t loop_start_time); + void after_loop_tasks_(); void feed_wdt_arch_(); diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 00b1264ed0..e60e0728bc 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -54,6 +54,14 @@ class EntityBase { // Get/set this entity's icon std::string get_icon() const; void set_icon(const char *icon); + StringRef get_icon_ref() const { + static constexpr auto EMPTY_STRING = StringRef::from_lit(""); +#ifdef USE_ENTITY_ICON + return this->icon_c_str_ == nullptr ? EMPTY_STRING : StringRef(this->icon_c_str_); +#else + return EMPTY_STRING; +#endif + } #ifdef USE_DEVICES // Get/set this entity's device id @@ -105,6 +113,11 @@ class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming) std::string get_device_class(); /// Manually set the device class. void set_device_class(const char *device_class); + /// Get the device class as StringRef + StringRef get_device_class_ref() const { + static constexpr auto EMPTY_STRING = StringRef::from_lit(""); + return this->device_class_ == nullptr ? EMPTY_STRING : StringRef(this->device_class_); + } protected: const char *device_class_{nullptr}; ///< Device class override @@ -116,6 +129,11 @@ class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming) std::string get_unit_of_measurement(); /// Manually set the unit of measurement. void set_unit_of_measurement(const char *unit_of_measurement); + /// Get the unit of measurement as StringRef + StringRef get_unit_of_measurement_ref() const { + static constexpr auto EMPTY_STRING = StringRef::from_lit(""); + return this->unit_of_measurement_ == nullptr ? EMPTY_STRING : StringRef(this->unit_of_measurement_); + } protected: const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 42dc433b64..24ee1aaa47 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -113,8 +113,15 @@ def force_str(force: bool) -> str: class TypeInfo(ABC): """Base class for all type information.""" - def __init__(self, field: descriptor.FieldDescriptorProto) -> None: + def __init__( + self, + field: descriptor.FieldDescriptorProto, + needs_decode: bool = True, + needs_encode: bool = True, + ) -> None: self._field = field + self._needs_decode = needs_decode + self._needs_encode = needs_encode @property def default_value(self) -> str: @@ -313,9 +320,16 @@ def validate_field_type(field_type: int, field_name: str = "") -> None: ) -def create_field_type_info(field: descriptor.FieldDescriptorProto) -> TypeInfo: +def create_field_type_info( + field: descriptor.FieldDescriptorProto, + needs_decode: bool = True, + needs_encode: bool = True, +) -> TypeInfo: """Create the appropriate TypeInfo instance for a field, handling repeated fields and custom options.""" if field.label == 3: # repeated + # Check if this repeated field has fixed_array_size option + if (fixed_size := get_field_opt(field, pb.fixed_array_size)) is not None: + return FixedArrayRepeatedType(field, fixed_size) return RepeatedTypeInfo(field) # Check for fixed_array_size option on bytes fields @@ -325,6 +339,14 @@ def create_field_type_info(field: descriptor.FieldDescriptorProto) -> TypeInfo: ): return FixedArrayBytesType(field, fixed_size) + # Special handling for bytes fields + if field.type == 12: + return BytesType(field, needs_decode, needs_encode) + + # Special handling for string fields + if field.type == 9: + return StringType(field, needs_decode, needs_encode) + validate_field_type(field.type, field.name) return TYPE_INFO[field.type](field) @@ -525,12 +547,67 @@ class StringType(TypeInfo): encode_func = "encode_string" wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2 + @property + def public_content(self) -> list[str]: + content: list[str] = [] + # Add std::string storage if message needs decoding + if self._needs_decode: + content.append(f"std::string {self.field_name}{{}};") + + if self._needs_encode: + content.extend( + [ + # Add StringRef field if message needs encoding + f"StringRef {self.field_name}_ref_{{}};", + # Add setter method if message needs encoding + f"void set_{self.field_name}(const StringRef &ref) {{", + f" this->{self.field_name}_ref_ = ref;", + "}", + ] + ) + return content + + @property + def encode_content(self) -> str: + return f"buffer.encode_string({self.number}, this->{self.field_name}_ref_);" + def dump(self, name): - o = f'out.append("\'").append({name}).append("\'");' - return o + # If name is 'it', this is a repeated field element - always use string + if name == "it": + return "append_quoted_string(out, StringRef(it));" + + # For SOURCE_CLIENT only, always use std::string + if not self._needs_encode: + return f'out.append("\'").append(this->{self.field_name}).append("\'");' + + # For SOURCE_SERVER, always use StringRef + if not self._needs_decode: + return f"append_quoted_string(out, this->{self.field_name}_ref_);" + + # For SOURCE_BOTH, check if StringRef is set (sending) or use string (received) + return ( + f"if (!this->{self.field_name}_ref_.empty()) {{" + f' out.append("\'").append(this->{self.field_name}_ref_.c_str()).append("\'");' + f"}} else {{" + f' out.append("\'").append(this->{self.field_name}).append("\'");' + f"}}" + ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_string_field") + # For SOURCE_CLIENT only messages, use the string field directly + if not self._needs_encode: + return self._get_simple_size_calculation(name, force, "add_string_field") + + # 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_string_field_repeated which includes field ID + field_id_size = self.calculate_field_id_size() + return f"ProtoSize::add_string_field_repeated(total_size, {field_id_size}, it);" + + # For messages that need encoding, use the StringRef size + field_id_size = self.calculate_field_id_size() + return f"ProtoSize::add_string_field(total_size, {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 @@ -578,6 +655,8 @@ class MessageType(TypeInfo): return self._get_simple_size_calculation(name, force, "add_message_object") def get_estimated_size(self) -> int: + # For message types, we can't easily estimate the submessage size without + # access to the actual message definition. This is just a rough estimate. return ( self.calculate_field_id_size() + 16 ) # field ID + 16 bytes estimated submessage @@ -589,20 +668,59 @@ class BytesType(TypeInfo): default_value = "" reference_type = "std::string &" const_reference_type = "const std::string &" - decode_length = "value.as_string()" encode_func = "encode_bytes" + decode_length = "value.as_string()" wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2 + @property + def public_content(self) -> list[str]: + content: list[str] = [] + # Add std::string storage if message needs decoding + if self._needs_decode: + content.append(f"std::string {self.field_name}{{}};") + + if self._needs_encode: + content.extend( + [ + # Add pointer/length fields if message needs encoding + f"const uint8_t* {self.field_name}_ptr_{{nullptr}};", + f"size_t {self.field_name}_len_{{0}};", + # Add setter method if message needs encoding + f"void set_{self.field_name}(const uint8_t* data, size_t len) {{", + f" this->{self.field_name}_ptr_ = data;", + f" this->{self.field_name}_len_ = len;", + "}", + ] + ) + return content + @property def encode_content(self) -> str: - return f"buffer.encode_bytes({self.number}, reinterpret_cast(this->{self.field_name}.data()), this->{self.field_name}.size());" + return f"buffer.encode_bytes({self.number}, this->{self.field_name}_ptr_, this->{self.field_name}_len_);" def dump(self, name: str) -> str: - o = f"out.append(format_hex_pretty({name}));" - return o + ptr_dump = f"format_hex_pretty(this->{self.field_name}_ptr_, this->{self.field_name}_len_)" + str_dump = f"format_hex_pretty(reinterpret_cast(this->{self.field_name}.data()), this->{self.field_name}.size())" + + # For SOURCE_CLIENT only, always use std::string + if not self._needs_encode: + return f"out.append({str_dump});" + + # For SOURCE_SERVER, always use pointer/length + if not self._needs_decode: + return f"out.append({ptr_dump});" + + # For SOURCE_BOTH, check if pointer is set (sending) or use string (received) + return ( + f"if (this->{self.field_name}_ptr_ != nullptr) {{\n" + f" out.append({ptr_dump});\n" + f" }} else {{\n" + f" out.append({str_dump});\n" + f" }}" + ) def get_size_calculation(self, name: str, force: bool = False) -> str: - return self._get_simple_size_calculation(name, force, "add_string_field") + return f"ProtoSize::add_bytes_field(total_size, {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 @@ -829,6 +947,111 @@ class SInt64Type(TypeInfo): return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint +class FixedArrayRepeatedType(TypeInfo): + """Special type for fixed-size repeated fields using std::array. + + Fixed arrays are only supported for encoding (SOURCE_SERVER) since we cannot + control how many items we receive when decoding. + """ + + def __init__(self, field: descriptor.FieldDescriptorProto, size: int) -> None: + super().__init__(field) + self.array_size = size + # Create the element type info + validate_field_type(field.type, field.name) + self._ti: TypeInfo = TYPE_INFO[field.type](field) + + @property + def cpp_type(self) -> str: + return f"std::array<{self._ti.cpp_type}, {self.array_size}>" + + @property + def reference_type(self) -> str: + return f"{self.cpp_type} &" + + @property + def const_reference_type(self) -> str: + return f"const {self.cpp_type} &" + + @property + def wire_type(self) -> WireType: + """Get the wire type for this fixed array field.""" + return self._ti.wire_type + + @property + def public_content(self) -> list[str]: + # Just the array member, no index needed since we don't decode + return [f"{self.cpp_type} {self.field_name}{{}};"] + + # No decode methods needed - fixed arrays don't support decoding + # The base class TypeInfo already returns None for all decode properties + + @property + def encode_content(self) -> str: + # Helper to generate encode statement for a single element + def encode_element(element: str) -> str: + if isinstance(self._ti, EnumType): + return f"buffer.{self._ti.encode_func}({self.number}, static_cast({element}), true);" + else: + return f"buffer.{self._ti.encode_func}({self.number}, {element}, true);" + + # Unroll small arrays for efficiency + if self.array_size == 1: + return encode_element(f"this->{self.field_name}[0]") + elif self.array_size == 2: + return ( + encode_element(f"this->{self.field_name}[0]") + + "\n " + + encode_element(f"this->{self.field_name}[1]") + ) + + # Use loops for larger arrays + o = f"for (const auto &it : this->{self.field_name}) {{\n" + o += f" {encode_element('it')}\n" + o += "}" + return o + + @property + def dump_content(self) -> str: + o = f"for (const auto &it : this->{self.field_name}) {{\n" + o += f' out.append(" {self.name}: ");\n' + o += indent(self._ti.dump("it")) + "\n" + o += ' out.append("\\n");\n' + o += "}\n" + return o + + def dump(self, name: str) -> str: + # This is used when dumping the array itself (not its elements) + # Since dump_content handles the iteration, this is not used directly + return "" + + def get_size_calculation(self, name: str, force: bool = False) -> str: + # For fixed arrays, we always encode all elements + + # Special case for single-element arrays - no loop needed + if self.array_size == 1: + return self._ti.get_size_calculation(f"{name}[0]", True) + + # Special case for 2-element arrays - unroll the calculation + if self.array_size == 2: + return ( + self._ti.get_size_calculation(f"{name}[0]", True) + + "\n " + + self._ti.get_size_calculation(f"{name}[1]", True) + ) + + # Use loops for larger arrays + o = f"for (const auto &it : {name}) {{\n" + o += f" {self._ti.get_size_calculation('it', True)}\n" + o += "}" + return o + + def get_estimated_size(self) -> int: + # For fixed arrays, estimate underlying type size * array size + underlying_size = self._ti.get_estimated_size() + return underlying_size * self.array_size + + class RepeatedTypeInfo(TypeInfo): def __init__(self, field: descriptor.FieldDescriptorProto) -> None: super().__init__(field) @@ -1257,7 +1480,20 @@ def build_message_type( if field.options.deprecated: continue - ti = create_field_type_info(field) + # Validate that fixed_array_size is only used in encode-only messages + if ( + needs_decode + and field.label == 3 + and get_field_opt(field, pb.fixed_array_size) is not None + ): + raise ValueError( + f"Message '{desc.name}' uses fixed_array_size on field '{field.name}' " + f"but has source={SOURCE_NAMES[source]}. " + f"Fixed arrays are only supported for SOURCE_SERVER (encode-only) messages " + f"since we cannot trust or control the number of items received from clients." + ) + + ti = create_field_type_info(field, needs_decode, needs_encode) # Skip field declarations for fields that are in the base class # but include their encode/decode logic @@ -1446,6 +1682,12 @@ SOURCE_BOTH = 0 SOURCE_SERVER = 1 SOURCE_CLIENT = 2 +SOURCE_NAMES = { + SOURCE_BOTH: "SOURCE_BOTH", + SOURCE_SERVER: "SOURCE_SERVER", + SOURCE_CLIENT: "SOURCE_CLIENT", +} + RECEIVE_CASES: dict[int, tuple[str, str | None]] = {} ifdefs: dict[str, str] = {} @@ -1572,10 +1814,20 @@ def build_base_class( public_content = [] protected_content = [] + # Determine if any message using this base class needs decoding/encoding + needs_decode = any( + message_source_map.get(msg.name, SOURCE_BOTH) in (SOURCE_BOTH, SOURCE_CLIENT) + for msg in messages + ) + needs_encode = any( + message_source_map.get(msg.name, SOURCE_BOTH) in (SOURCE_BOTH, SOURCE_SERVER) + for msg in messages + ) + # For base classes, we only declare the fields but don't handle encode/decode # The derived classes will handle encoding/decoding with their specific field numbers for field in common_fields: - ti = create_field_type_info(field) + ti = create_field_type_info(field, needs_decode, needs_encode) # Get field_ifdef if it's consistent across all messages field_ifdef = get_common_field_ifdef(field.name, messages) @@ -1586,12 +1838,6 @@ def build_base_class( if ti.public_content: public_content.extend(wrap_with_ifdef(ti.public_content, field_ifdef)) - # Determine if any message using this base class needs decoding - needs_decode = any( - message_source_map.get(msg.name, SOURCE_BOTH) in (SOURCE_BOTH, SOURCE_CLIENT) - for msg in messages - ) - # Build header parent_class = "ProtoDecodableMessage" if needs_decode else "ProtoMessage" out = f"class {base_class_name} : public {parent_class} {{\n" @@ -1715,6 +1961,7 @@ def main() -> None: #pragma once #include "esphome/core/defines.h" +#include "esphome/core/string_ref.h" #include "proto.h" @@ -1748,6 +1995,15 @@ namespace api { namespace esphome { namespace api { +// Helper function to append a quoted string, handling empty StringRef +static inline void append_quoted_string(std::string &out, const StringRef &ref) { + out.append("'"); + if (!ref.empty()) { + out.append(ref.c_str()); + } + out.append("'"); +} + """ content += "namespace enums {\n\n" @@ -1988,7 +2244,13 @@ static const char *const TAG = "api.service"; cpp += f"#ifdef {ifdef}\n" hpp_protected += f" void {on_func}(const {inp} &msg) override;\n" - hpp += f" virtual {ret} {func}(const {inp} &msg) = 0;\n" + + # For non-void methods, generate a send_ method instead of return-by-value + if is_void: + hpp += f" virtual void {func}(const {inp} &msg) = 0;\n" + else: + hpp += f" virtual bool send_{func}_response(const {inp} &msg) = 0;\n" + cpp += f"void {class_name}::{on_func}(const {inp} &msg) {{\n" # Start with authentication/connection check if needed @@ -2006,10 +2268,7 @@ static const char *const TAG = "api.service"; if is_void: handler_body = f"this->{func}(msg);\n" else: - handler_body = f"{ret} ret = this->{func}(msg);\n" - handler_body += ( - f"if (!this->send_message(ret, {ret}::MESSAGE_TYPE)) {{\n" - ) + handler_body = f"if (!this->send_{func}_response(msg)) {{\n" handler_body += " this->on_fatal_error();\n" handler_body += "}\n" @@ -2021,8 +2280,7 @@ static const char *const TAG = "api.service"; if is_void: body += f"this->{func}(msg);\n" else: - body += f"{ret} ret = this->{func}(msg);\n" - body += f"if (!this->send_message(ret, {ret}::MESSAGE_TYPE)) {{\n" + body += f"if (!this->send_{func}_response(msg)) {{\n" body += " this->on_fatal_error();\n" body += "}\n" diff --git a/tests/component_tests/mipi_spi/test_init.py b/tests/component_tests/mipi_spi/test_init.py index 96abad02ad..9824852653 100644 --- a/tests/component_tests/mipi_spi/test_init.py +++ b/tests/component_tests/mipi_spi/test_init.py @@ -266,7 +266,7 @@ def test_framework_specific_errors( with pytest.raises( cv.Invalid, - match=r"This feature is only available with frameworks \['esp-idf'\]", + match=r"This feature is only available with framework\(s\) esp-idf", ): run_schema_validation({"model": "wt32-sc01-plus"})