mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 02:56:01 +00:00
[core] Replace Application name/friendly_name with StringRef
Replace std::string members with StringRef for Application::name_ and Application::friendly_name_. These are set once during setup() and never modified, so std::string overhead is unnecessary. For the MAC suffix case, codegen emits static mutable char buffers with a placeholder suffix that pre_setup() overwrites with the actual MAC address. For the non-suffix case, StringRef points directly at the string literal. Saves ~2.5KB flash and ~48 bytes RAM by eliminating std::string template instantiations (constructor, _M_assign, _M_dispose, _M_construct, _M_replace_cold, _S_copy).
This commit is contained in:
@@ -269,7 +269,7 @@ APIError APINoiseFrameHelper::state_action_() {
|
||||
}
|
||||
if (state_ == State::SERVER_HELLO) {
|
||||
// send server hello
|
||||
const std::string &name = App.get_name();
|
||||
const StringRef &name = App.get_name();
|
||||
char mac[MAC_ADDRESS_BUFFER_SIZE];
|
||||
get_mac_address_into_buffer(mac);
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ bool ESP32BLE::ble_setup_() {
|
||||
device_name = this->name_;
|
||||
}
|
||||
} else {
|
||||
const std::string &app_name = App.get_name();
|
||||
const StringRef &app_name = App.get_name();
|
||||
size_t name_len = app_name.length();
|
||||
if (name_len > 20) {
|
||||
if (App.is_name_add_mac_suffix_enabled()) {
|
||||
|
||||
@@ -59,7 +59,7 @@ void MDNSComponent::compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUN
|
||||
service.proto = MDNS_STR(SERVICE_TCP);
|
||||
service.port = api::global_api_server->get_port();
|
||||
|
||||
const std::string &friendly_name = App.get_friendly_name();
|
||||
const StringRef &friendly_name = App.get_friendly_name();
|
||||
bool friendly_name_empty = friendly_name.empty();
|
||||
|
||||
// Calculate exact capacity for txt_records
|
||||
|
||||
@@ -268,7 +268,7 @@ bool MQTTComponent::send_discovery_() {
|
||||
root[MQTT_UNIQUE_ID] = unique_id_buf;
|
||||
}
|
||||
|
||||
const std::string &node_name = App.get_name();
|
||||
const StringRef &node_name = App.get_name();
|
||||
if (discovery_info.object_id_generator == MQTT_DEVICE_NAME_OBJECT_ID_GENERATOR) {
|
||||
// node_name (max 31) + "_" (1) + object_id (max 128) + null
|
||||
char object_id_full[ESPHOME_DEVICE_NAME_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 1];
|
||||
@@ -276,8 +276,8 @@ bool MQTTComponent::send_discovery_() {
|
||||
root[MQTT_OBJECT_ID] = object_id_full;
|
||||
}
|
||||
|
||||
const std::string &friendly_name_ref = App.get_friendly_name();
|
||||
const std::string &node_friendly_name = friendly_name_ref.empty() ? node_name : friendly_name_ref;
|
||||
const StringRef &friendly_name_ref = App.get_friendly_name();
|
||||
const StringRef &node_friendly_name = friendly_name_ref.empty() ? node_name : friendly_name_ref;
|
||||
const char *node_area = App.get_area();
|
||||
|
||||
JsonObject device_info = root[MQTT_DEVICE].to<JsonObject>();
|
||||
|
||||
@@ -132,7 +132,7 @@ void OpenThreadSrpComponent::setup() {
|
||||
// set the host name
|
||||
uint16_t size;
|
||||
char *existing_host_name = otSrpClientBuffersGetHostNameString(instance, &size);
|
||||
const std::string &host_name = App.get_name();
|
||||
const StringRef &host_name = App.get_name();
|
||||
uint16_t host_name_len = host_name.size();
|
||||
if (host_name_len > size) {
|
||||
ESP_LOGW(TAG, "Hostname is too long, choose a shorter project name");
|
||||
|
||||
@@ -75,7 +75,7 @@ void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; }
|
||||
|
||||
void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *stream = request->beginResponseStream(ESPHOME_F("text/html"));
|
||||
const std::string &title = App.get_name();
|
||||
const StringRef &title = App.get_name();
|
||||
stream->print(ESPHOME_F("<!DOCTYPE html><html lang=\"en\"><head><meta charset=UTF-8><meta "
|
||||
"name=viewport content=\"width=device-width, initial-scale=1,user-scalable=no\"><title>"));
|
||||
stream->print(title.c_str());
|
||||
|
||||
@@ -913,7 +913,7 @@ void WiFiComponent::setup_ap_config_() {
|
||||
static constexpr size_t AP_SSID_PREFIX_LEN = 25;
|
||||
static constexpr size_t AP_SSID_SUFFIX_LEN = 7;
|
||||
|
||||
const std::string &app_name = App.get_name();
|
||||
const StringRef &app_name = App.get_name();
|
||||
const char *name_ptr = app_name.c_str();
|
||||
size_t name_len = app_name.length();
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
|
||||
return addresses;
|
||||
}
|
||||
bool WiFiComponent::wifi_apply_hostname_() {
|
||||
const std::string &hostname = App.get_name();
|
||||
const StringRef &hostname = App.get_name();
|
||||
bool ret = wifi_station_set_hostname(const_cast<char *>(hostname.c_str()));
|
||||
if (!ret) {
|
||||
ESP_LOGV(TAG, "Set hostname failed");
|
||||
|
||||
+13
-13
@@ -138,7 +138,7 @@ static constexpr uint32_t TEARDOWN_TIMEOUT_REBOOT_MS = 1000; // 1 second for qu
|
||||
|
||||
class Application {
|
||||
public:
|
||||
void pre_setup(const std::string &name, const std::string &friendly_name, bool name_add_mac_suffix) {
|
||||
void pre_setup(char *name, size_t name_len, char *friendly_name, size_t friendly_name_len, bool name_add_mac_suffix) {
|
||||
arch_init();
|
||||
this->name_add_mac_suffix_ = name_add_mac_suffix;
|
||||
if (name_add_mac_suffix) {
|
||||
@@ -148,15 +148,15 @@ class Application {
|
||||
constexpr size_t mac_address_suffix_len = 6;
|
||||
char mac_addr[mac_address_len];
|
||||
get_mac_address_into_buffer(mac_addr);
|
||||
const char *mac_suffix_ptr = mac_addr + mac_address_suffix_len;
|
||||
this->name_ = make_name_with_suffix(name, '-', mac_suffix_ptr, mac_address_suffix_len);
|
||||
if (!friendly_name.empty()) {
|
||||
this->friendly_name_ = make_name_with_suffix(friendly_name, ' ', mac_suffix_ptr, mac_address_suffix_len);
|
||||
// Overwrite the placeholder suffix in the static buffers with actual MAC
|
||||
memcpy(name + name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len, mac_address_suffix_len);
|
||||
if (friendly_name_len > 0) {
|
||||
memcpy(friendly_name + friendly_name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len,
|
||||
mac_address_suffix_len);
|
||||
}
|
||||
} else {
|
||||
this->name_ = name;
|
||||
this->friendly_name_ = friendly_name;
|
||||
}
|
||||
this->name_ = StringRef(name, name_len);
|
||||
this->friendly_name_ = StringRef(friendly_name, friendly_name_len);
|
||||
}
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
@@ -274,10 +274,10 @@ class Application {
|
||||
void loop();
|
||||
|
||||
/// Get the name of this Application set by pre_setup().
|
||||
const std::string &get_name() const { return this->name_; }
|
||||
const StringRef &get_name() const { return this->name_; }
|
||||
|
||||
/// Get the friendly name of this Application set by pre_setup().
|
||||
const std::string &get_friendly_name() const { return this->friendly_name_; }
|
||||
const StringRef &get_friendly_name() const { return this->friendly_name_; }
|
||||
|
||||
/// Get the area of this Application set by pre_setup().
|
||||
const char *get_area() const {
|
||||
@@ -627,9 +627,9 @@ class Application {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// std::string members (typically 24-32 bytes each)
|
||||
std::string name_;
|
||||
std::string friendly_name_;
|
||||
// StringRef members (8 bytes each: pointer + size)
|
||||
StringRef name_;
|
||||
StringRef friendly_name_;
|
||||
|
||||
// 4-byte members
|
||||
uint32_t last_loop_{0};
|
||||
|
||||
+42
-3
@@ -50,6 +50,7 @@ from esphome.core import (
|
||||
)
|
||||
from esphome.helpers import (
|
||||
copy_file_if_changed,
|
||||
cpp_string_escape,
|
||||
fnv1a_32bit_hash,
|
||||
get_str_env,
|
||||
walk_files,
|
||||
@@ -58,6 +59,12 @@ from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# C++ variable names and separators for app name buffers (used with MAC suffix)
|
||||
_APP_NAME_BUF_VAR = "esphome_app_name_buf"
|
||||
_APP_NAME_MAC_SEP = "-"
|
||||
_APP_FRIENDLY_NAME_BUF_VAR = "esphome_app_friendly_name_buf"
|
||||
_APP_FRIENDLY_NAME_MAC_SEP = " "
|
||||
|
||||
StartupTrigger = cg.esphome_ns.class_(
|
||||
"StartupTrigger", cg.Component, automation.Trigger.template()
|
||||
)
|
||||
@@ -551,11 +558,43 @@ async def to_code(config: ConfigType) -> None:
|
||||
# Construct App via placement new — see application.cpp for storage details
|
||||
cg.add_global(cg.RawStatement("#include <new>"))
|
||||
cg.add(cg.RawExpression("new (&App) Application()"))
|
||||
name = config[CONF_NAME]
|
||||
friendly_name = config[CONF_FRIENDLY_NAME]
|
||||
name_add_mac_suffix = config[CONF_NAME_ADD_MAC_SUFFIX]
|
||||
|
||||
def _make_app_name_expr(
|
||||
value: str, var_name: str, sep: str
|
||||
) -> tuple[cg.Expression, int]:
|
||||
"""Create a name expression for pre_setup.
|
||||
|
||||
With MAC suffix: emits a static mutable buffer with placeholder suffix.
|
||||
Without: casts the string literal to char*.
|
||||
Returns (expression, length).
|
||||
"""
|
||||
if not value:
|
||||
return cg.RawExpression('(char *) ""'), 0
|
||||
if name_add_mac_suffix:
|
||||
value_with_placeholder = f"{value}{sep}XXXXXX"
|
||||
cg.add_global(
|
||||
cg.RawStatement(
|
||||
f"static char {var_name}[] = {cpp_string_escape(value_with_placeholder)};"
|
||||
)
|
||||
)
|
||||
return cg.RawExpression(var_name), len(value_with_placeholder)
|
||||
return (
|
||||
cg.RawExpression(f"(char *) {cpp_string_escape(value)}"),
|
||||
len(value),
|
||||
)
|
||||
|
||||
name_expr, name_len = _make_app_name_expr(
|
||||
name, _APP_NAME_BUF_VAR, _APP_NAME_MAC_SEP
|
||||
)
|
||||
friendly_expr, friendly_len = _make_app_name_expr(
|
||||
friendly_name, _APP_FRIENDLY_NAME_BUF_VAR, _APP_FRIENDLY_NAME_MAC_SEP
|
||||
)
|
||||
cg.add(
|
||||
cg.App.pre_setup(
|
||||
config[CONF_NAME],
|
||||
config[CONF_FRIENDLY_NAME],
|
||||
config[CONF_NAME_ADD_MAC_SUFFIX],
|
||||
name_expr, name_len, friendly_expr, friendly_len, name_add_mac_suffix
|
||||
)
|
||||
)
|
||||
# Define component count for static allocation
|
||||
|
||||
@@ -22,13 +22,13 @@ void EntityBase::set_name(const char *name, uint32_t object_id_hash) {
|
||||
// Bug-for-bug compatibility with OLD behavior:
|
||||
// - With MAC suffix: OLD code used App.get_friendly_name() directly (no fallback)
|
||||
// - Without MAC suffix: OLD code used pre-computed object_id with fallback to device name
|
||||
const std::string &friendly = App.get_friendly_name();
|
||||
const StringRef &friendly = App.get_friendly_name();
|
||||
if (App.is_name_add_mac_suffix_enabled()) {
|
||||
// MAC suffix enabled - use friendly_name directly (even if empty) for compatibility
|
||||
this->name_ = StringRef(friendly);
|
||||
this->name_ = friendly;
|
||||
} else {
|
||||
// No MAC suffix - fallback to device name if friendly_name is empty
|
||||
this->name_ = StringRef(!friendly.empty() ? friendly : App.get_name());
|
||||
this->name_ = !friendly.empty() ? friendly : App.get_name();
|
||||
}
|
||||
}
|
||||
this->flags_.has_own_name = false;
|
||||
|
||||
Reference in New Issue
Block a user