zero_copy_str

This commit is contained in:
J. Nick Koston
2025-07-21 17:02:01 -10:00
parent b17e2019c7
commit c4ac22286f
12 changed files with 1483 additions and 558 deletions

View File

@@ -248,8 +248,8 @@ void APIConnection::loop() {
if (state_subs_at_ < static_cast<int>(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(it.entity_id.c_str(), it.entity_id.length());
resp.set_attribute(it.attribute.value().c_str(), it.attribute.value().length());
resp.once = it.once;
if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
state_subs_at_++;
@@ -344,7 +344,8 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne
bool is_single) {
auto *binary_sensor = static_cast<binary_sensor::BinarySensor *>(entity);
ListEntitiesBinarySensorResponse msg;
msg.device_class = binary_sensor->get_device_class();
const std::string &device_class = binary_sensor->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
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);
@@ -376,7 +377,8 @@ 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();
const std::string &device_class = cover->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
return fill_and_encode_entity_info(cover, msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -411,7 +413,7 @@ uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *co
if (traits.supports_direction())
msg.direction = static_cast<enums::FanDirection>(fan->direction);
if (traits.supports_preset_modes())
msg.preset_mode = fan->preset_mode;
msg.set_preset_mode(fan->preset_mode.c_str(), fan->preset_mode.length());
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,
@@ -468,8 +470,10 @@ 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()) {
const std::string &effect_name = light->get_effect_name();
resp.set_effect(effect_name.c_str(), effect_name.length());
}
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,
@@ -545,10 +549,12 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *
bool is_single) {
auto *sensor = static_cast<sensor::Sensor *>(entity);
ListEntitiesSensorResponse msg;
msg.unit_of_measurement = sensor->get_unit_of_measurement();
const std::string &unit = sensor->get_unit_of_measurement();
msg.set_unit_of_measurement(unit.c_str(), unit.length());
msg.accuracy_decimals = sensor->get_accuracy_decimals();
msg.force_update = sensor->get_force_update();
msg.device_class = sensor->get_device_class();
const std::string &device_class = sensor->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
msg.state_class = static_cast<enums::SensorStateClass>(sensor->get_state_class());
return fill_and_encode_entity_info(sensor, msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
@@ -575,7 +581,8 @@ uint16_t APIConnection::try_send_switch_info(EntityBase *entity, APIConnection *
auto *a_switch = static_cast<switch_::Switch *>(entity);
ListEntitiesSwitchResponse msg;
msg.assumed_state = a_switch->assumed_state();
msg.device_class = a_switch->get_device_class();
const std::string &device_class = a_switch->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
return fill_and_encode_entity_info(a_switch, msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -600,7 +607,7 @@ uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnec
bool is_single) {
auto *text_sensor = static_cast<text_sensor::TextSensor *>(entity);
TextSensorStateResponse resp;
resp.state = text_sensor->state;
resp.set_state(text_sensor->state.c_str(), text_sensor->state.length());
resp.missing_state = !text_sensor->has_state();
return fill_and_encode_entity_state(text_sensor, resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
@@ -609,7 +616,8 @@ uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnect
bool is_single) {
auto *text_sensor = static_cast<text_sensor::TextSensor *>(entity);
ListEntitiesTextSensorResponse msg;
msg.device_class = text_sensor->get_device_class();
const std::string &device_class = text_sensor->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
return fill_and_encode_entity_info(text_sensor, msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn,
remaining_size, is_single);
}
@@ -637,13 +645,17 @@ 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<enums::ClimateFanMode>(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()) {
const std::string &custom_fan = climate->custom_fan_mode.value();
resp.set_custom_fan_mode(custom_fan.c_str(), custom_fan.length());
}
if (traits.get_supports_presets() && climate->preset.has_value()) {
resp.preset = static_cast<enums::ClimatePreset>(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()) {
const std::string &custom_preset = climate->custom_preset.value();
resp.set_custom_preset(custom_preset.c_str(), custom_preset.length());
}
if (traits.get_supports_swing_modes())
resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
if (traits.get_supports_current_humidity())
@@ -729,9 +741,11 @@ uint16_t APIConnection::try_send_number_info(EntityBase *entity, APIConnection *
bool is_single) {
auto *number = static_cast<number::Number *>(entity);
ListEntitiesNumberResponse msg;
msg.unit_of_measurement = number->traits.get_unit_of_measurement();
const std::string &unit = number->traits.get_unit_of_measurement();
msg.set_unit_of_measurement(unit.c_str(), unit.length());
msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
msg.device_class = number->traits.get_device_class();
const std::string &device_class = number->traits.get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
msg.min_value = number->traits.get_min_value();
msg.max_value = number->traits.get_max_value();
msg.step = number->traits.get_step();
@@ -844,7 +858,7 @@ uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *c
bool is_single) {
auto *text = static_cast<text::Text *>(entity);
TextStateResponse resp;
resp.state = text->state;
resp.set_state(text->state.c_str(), text->state.length());
resp.missing_state = !text->has_state();
return fill_and_encode_entity_state(text, resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
@@ -856,7 +870,8 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co
msg.mode = static_cast<enums::TextMode>(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();
const std::string &pattern = text->traits.get_pattern();
msg.set_pattern(pattern.c_str(), pattern.length());
return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -877,7 +892,7 @@ uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection
bool is_single) {
auto *select = static_cast<select::Select *>(entity);
SelectStateResponse resp;
resp.state = select->state;
resp.set_state(select->state.c_str(), select->state.length());
resp.missing_state = !select->has_state();
return fill_and_encode_entity_state(select, resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
@@ -903,7 +918,8 @@ uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *
bool is_single) {
auto *button = static_cast<button::Button *>(entity);
ListEntitiesButtonResponse msg;
msg.device_class = button->get_device_class();
const std::string &device_class = button->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
return fill_and_encode_entity_info(button, msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -972,7 +988,8 @@ uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *c
auto *valve = static_cast<valve::Valve *>(entity);
ListEntitiesValveResponse msg;
auto traits = valve->get_traits();
msg.device_class = valve->get_device_class();
const std::string &device_class = valve->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
msg.assumed_state = traits.get_is_assumed_state();
msg.supports_position = traits.get_supports_position();
msg.supports_stop = traits.get_supports_stop();
@@ -1273,7 +1290,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(event_type.c_str(), event_type.length());
return fill_and_encode_entity_state(event, resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
@@ -1281,7 +1298,8 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c
bool is_single) {
auto *event = static_cast<event::Event *>(entity);
ListEntitiesEventResponse msg;
msg.device_class = event->get_device_class();
const std::string &device_class = event->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
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,
@@ -1305,11 +1323,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(update->update_info.current_version.c_str(), update->update_info.current_version.length());
resp.set_latest_version(update->update_info.latest_version.c_str(), update->update_info.latest_version.length());
resp.set_title(update->update_info.title.c_str(), update->update_info.title.length());
resp.set_release_summary(update->update_info.summary.c_str(), update->update_info.summary.length());
resp.set_release_url(update->update_info.release_url.c_str(), update->update_info.release_url.length());
}
return fill_and_encode_entity_state(update, resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
@@ -1317,7 +1335,8 @@ uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *
bool is_single) {
auto *update = static_cast<update::UpdateEntity *>(entity);
ListEntitiesUpdateResponse msg;
msg.device_class = update->get_device_class();
const std::string &device_class = update->get_device_class();
msg.set_device_class(device_class.c_str(), device_class.length());
return fill_and_encode_entity_info(update, msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -1377,8 +1396,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();
std::string server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.set_server_info(server_info.c_str(), server_info.length());
const std::string &name = App.get_name();
resp.set_name(name.c_str(), name.length());
#ifdef USE_API_PASSWORD
// Password required - wait for authentication
@@ -1409,41 +1430,47 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
#ifdef USE_API_PASSWORD
resp.uses_password = true;
#endif
resp.name = App.get_name();
resp.friendly_name = App.get_friendly_name();
const std::string &name = App.get_name();
resp.set_name(name.c_str(), name.length());
const std::string &friendly_name = App.get_friendly_name();
resp.set_friendly_name(friendly_name.c_str(), friendly_name.length());
#ifdef USE_AREAS
resp.suggested_area = App.get_area();
const std::string &area = App.get_area();
resp.set_suggested_area(area.c_str(), area.length());
#endif
resp.mac_address = get_mac_address_pretty();
resp.esphome_version = ESPHOME_VERSION;
resp.compilation_time = App.get_compilation_time();
std::string mac = get_mac_address_pretty();
resp.set_mac_address(mac.c_str(), mac.length());
resp.set_esphome_version(ESPHOME_VERSION, strlen(ESPHOME_VERSION));
const std::string &compilation_time = App.get_compilation_time();
resp.set_compilation_time(compilation_time.c_str(), compilation_time.length());
#if defined(USE_ESP8266) || defined(USE_ESP32)
resp.manufacturer = "Espressif";
resp.set_manufacturer("Espressif", 9);
#elif defined(USE_RP2040)
resp.manufacturer = "Raspberry Pi";
resp.set_manufacturer("Raspberry Pi", 12);
#elif defined(USE_BK72XX)
resp.manufacturer = "Beken";
resp.set_manufacturer("Beken", 5);
#elif defined(USE_LN882X)
resp.manufacturer = "Lightning";
resp.set_manufacturer("Lightning", 9);
#elif defined(USE_RTL87XX)
resp.manufacturer = "Realtek";
resp.set_manufacturer("Realtek", 7);
#elif defined(USE_HOST)
resp.manufacturer = "Host";
resp.set_manufacturer("Host", 4);
#endif
resp.model = ESPHOME_BOARD;
resp.set_model(ESPHOME_BOARD, strlen(ESPHOME_BOARD));
#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;
resp.set_project_name(ESPHOME_PROJECT_NAME, strlen(ESPHOME_PROJECT_NAME));
resp.set_project_version(ESPHOME_PROJECT_VERSION, strlen(ESPHOME_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();
std::string bt_mac = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty();
resp.set_bluetooth_mac_address(bt_mac.c_str(), bt_mac.length());
#endif
#ifdef USE_VOICE_ASSISTANT
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
@@ -1453,19 +1480,21 @@ 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();
const std::string &device_name = device->get_name();
device_info.set_name(device_name.c_str(), device_name.length());
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);
const std::string &area_name = area->get_name();
area_info.set_name(area_name.c_str(), area_name.length());
}
#endif
return resp;