mirror of
https://github.com/esphome/esphome.git
synced 2026-05-30 15:28:34 +08:00
[improv_base] Optimize next_url to avoid STL string operations (#13015)
This commit is contained in:
@@ -398,9 +398,12 @@ void ESP32ImprovComponent::check_wifi_connection_() {
|
|||||||
|
|
||||||
#ifdef USE_ESP32_IMPROV_NEXT_URL
|
#ifdef USE_ESP32_IMPROV_NEXT_URL
|
||||||
// Add next_url if configured (should be first per Improv BLE spec)
|
// Add next_url if configured (should be first per Improv BLE spec)
|
||||||
std::string next_url = this->get_formatted_next_url_();
|
{
|
||||||
if (!next_url.empty()) {
|
char url_buffer[384];
|
||||||
url_strings[url_count++] = std::move(next_url);
|
size_t len = this->get_formatted_next_url_(url_buffer, sizeof(url_buffer));
|
||||||
|
if (len > 0) {
|
||||||
|
url_strings[url_count++] = std::string(url_buffer, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "improv_base.h"
|
#include "improv_base.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include "esphome/components/network/util.h"
|
#include "esphome/components/network/util.h"
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
@@ -13,37 +14,54 @@ static constexpr size_t DEVICE_NAME_PLACEHOLDER_LEN = sizeof(DEVICE_NAME_PLACEHO
|
|||||||
static constexpr const char IP_ADDRESS_PLACEHOLDER[] = "{{ip_address}}";
|
static constexpr const char IP_ADDRESS_PLACEHOLDER[] = "{{ip_address}}";
|
||||||
static constexpr size_t IP_ADDRESS_PLACEHOLDER_LEN = sizeof(IP_ADDRESS_PLACEHOLDER) - 1;
|
static constexpr size_t IP_ADDRESS_PLACEHOLDER_LEN = sizeof(IP_ADDRESS_PLACEHOLDER) - 1;
|
||||||
|
|
||||||
static void replace_all_in_place(std::string &str, const char *placeholder, size_t placeholder_len,
|
/// Copy src to dest, returning pointer past last written char. Stops at end or if src is null.
|
||||||
const std::string &replacement) {
|
static char *copy_to_buffer(char *dest, const char *end, const char *src) {
|
||||||
size_t pos = 0;
|
if (src == nullptr) {
|
||||||
const size_t replacement_len = replacement.length();
|
return dest;
|
||||||
while ((pos = str.find(placeholder, pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, placeholder_len, replacement);
|
|
||||||
pos += replacement_len;
|
|
||||||
}
|
}
|
||||||
|
while (*src != '\0' && dest < end) {
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ImprovBase::get_formatted_next_url_() {
|
size_t ImprovBase::get_formatted_next_url_(char *buffer, size_t buffer_size) {
|
||||||
if (this->next_url_.empty()) {
|
if (this->next_url_ == nullptr || buffer_size == 0) {
|
||||||
return "";
|
if (buffer_size > 0) {
|
||||||
|
buffer[0] = '\0';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string formatted_url = this->next_url_;
|
// Get IP address once for replacement
|
||||||
|
const char *ip_str = nullptr;
|
||||||
// Replace all occurrences of {{device_name}}
|
char ip_buffer[network::IP_ADDRESS_BUFFER_SIZE];
|
||||||
replace_all_in_place(formatted_url, DEVICE_NAME_PLACEHOLDER, DEVICE_NAME_PLACEHOLDER_LEN, App.get_name());
|
|
||||||
|
|
||||||
// Replace all occurrences of {{ip_address}}
|
|
||||||
for (auto &ip : network::get_ip_addresses()) {
|
for (auto &ip : network::get_ip_addresses()) {
|
||||||
if (ip.is_ip4()) {
|
if (ip.is_ip4()) {
|
||||||
replace_all_in_place(formatted_url, IP_ADDRESS_PLACEHOLDER, IP_ADDRESS_PLACEHOLDER_LEN, ip.str());
|
ip.str_to(ip_buffer);
|
||||||
|
ip_str = ip_buffer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: {{esphome_version}} is replaced at code generation time in Python
|
const char *device_name = App.get_name().c_str();
|
||||||
|
char *out = buffer;
|
||||||
|
const char *end = buffer + buffer_size - 1;
|
||||||
|
|
||||||
return formatted_url;
|
// Note: {{esphome_version}} is replaced at code generation time in Python
|
||||||
|
for (const char *p = this->next_url_; *p != '\0' && out < end;) {
|
||||||
|
if (strncmp(p, DEVICE_NAME_PLACEHOLDER, DEVICE_NAME_PLACEHOLDER_LEN) == 0) {
|
||||||
|
out = copy_to_buffer(out, end, device_name);
|
||||||
|
p += DEVICE_NAME_PLACEHOLDER_LEN;
|
||||||
|
} else if (ip_str != nullptr && strncmp(p, IP_ADDRESS_PLACEHOLDER, IP_ADDRESS_PLACEHOLDER_LEN) == 0) {
|
||||||
|
out = copy_to_buffer(out, end, ip_str);
|
||||||
|
p += IP_ADDRESS_PLACEHOLDER_LEN;
|
||||||
|
} else {
|
||||||
|
*out++ = *p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out = '\0';
|
||||||
|
return out - buffer;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <cstddef>
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -9,13 +9,14 @@ namespace improv_base {
|
|||||||
class ImprovBase {
|
class ImprovBase {
|
||||||
public:
|
public:
|
||||||
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
|
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
|
||||||
void set_next_url(const std::string &next_url) { this->next_url_ = next_url; }
|
void set_next_url(const char *next_url) { this->next_url_ = next_url; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
|
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
|
||||||
std::string get_formatted_next_url_();
|
/// Format next_url_ into buffer, replacing placeholders. Returns length written.
|
||||||
std::string next_url_;
|
size_t get_formatted_next_url_(char *buffer, size_t buffer_size);
|
||||||
|
const char *next_url_{nullptr};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -182,8 +182,12 @@ void ImprovSerialComponent::write_data_(const uint8_t *data, const size_t size)
|
|||||||
std::vector<uint8_t> ImprovSerialComponent::build_rpc_settings_response_(improv::Command command) {
|
std::vector<uint8_t> ImprovSerialComponent::build_rpc_settings_response_(improv::Command command) {
|
||||||
std::vector<std::string> urls;
|
std::vector<std::string> urls;
|
||||||
#ifdef USE_IMPROV_SERIAL_NEXT_URL
|
#ifdef USE_IMPROV_SERIAL_NEXT_URL
|
||||||
if (!this->next_url_.empty()) {
|
{
|
||||||
urls.push_back(this->get_formatted_next_url_());
|
char url_buffer[384];
|
||||||
|
size_t len = this->get_formatted_next_url_(url_buffer, sizeof(url_buffer));
|
||||||
|
if (len > 0) {
|
||||||
|
urls.emplace_back(url_buffer, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
|
|||||||
Reference in New Issue
Block a user