Compare commits

..

63 Commits

Author SHA1 Message Date
J. Nick Koston
0cccbd7797 Merge branch 'ota_base_extract' into ota_base_extract_bk 2025-07-01 16:33:42 -05:00
J. Nick Koston
e920ffbef3 preen 2025-07-01 16:33:27 -05:00
J. Nick Koston
31b5a9a127 Merge branch 'ota_base_extract' into ota_base_extract_bk 2025-07-01 16:30:16 -05:00
J. Nick Koston
6395567f2a type 2025-07-01 16:19:18 -05:00
J. Nick Koston
c8e7a945ae Apply suggestions from code review 2025-07-01 16:14:59 -05:00
J. Nick Koston
f2b5a8e3b1 tweak 2025-07-01 16:09:57 -05:00
J. Nick Koston
0a836c7001 tweak 2025-07-01 16:06:31 -05:00
J. Nick Koston
69819cdcc5 fix import 2025-07-01 15:58:54 -05:00
J. Nick Koston
1756017181 fix import 2025-07-01 15:50:34 -05:00
J. Nick Koston
11b5b00cd6 fix import 2025-07-01 15:47:25 -05:00
J. Nick Koston
2c349cad8b fix import 2025-07-01 15:46:39 -05:00
J. Nick Koston
08f563167f typing 2025-07-01 15:44:32 -05:00
J. Nick Koston
8713945c6a typing 2025-07-01 15:44:17 -05:00
J. Nick Koston
e7e6b7f89b typing 2025-07-01 15:44:08 -05:00
J. Nick Koston
4ec8cd9611 revert 2025-07-01 15:43:55 -05:00
J. Nick Koston
b89c5751b1 Merge branch 'ota_base_extract' of https://github.com/esphome/esphome into ota_base_extract 2025-07-01 15:43:42 -05:00
J. Nick Koston
9d1e68e45d Apply suggestions from code review 2025-07-01 15:42:28 -05:00
J. Nick Koston
bc0a248149 Merge branch 'ota_base_extract' of https://github.com/esphome/esphome into ota_base_extract 2025-07-01 15:40:49 -05:00
J. Nick Koston
ec99692963 Apply suggestions from code review 2025-07-01 15:40:40 -05:00
J. Nick Koston
77f7816114 Update esphome/components/ota/__init__.py 2025-07-01 15:40:18 -05:00
J. Nick Koston
f3e7a6887b revert 2025-07-01 15:40:08 -05:00
J. Nick Koston
401523c854 revert 2025-07-01 15:39:43 -05:00
J. Nick Koston
5b0c249272 revert 2025-07-01 15:38:47 -05:00
J. Nick Koston
3f650b2c15 more relos 2025-07-01 15:35:40 -05:00
J. Nick Koston
a1e3b67683 Update CODEOWNERS 2025-07-01 15:33:28 -05:00
J. Nick Koston
6e45b9d2dd fixes 2025-07-01 15:31:29 -05:00
J. Nick Koston
c008e6aa1c revert ota_base changes, move to platform 2025-07-01 15:28:11 -05:00
J. Nick Koston
9799a2b636 test 2025-07-01 13:47:59 -05:00
J. Nick Koston
099474053e cleanuip 2025-07-01 13:38:47 -05:00
J. Nick Koston
efafabed97 fix rp2040 2025-07-01 13:23:24 -05:00
J. Nick Koston
2d0c109dc1 Merge remote-tracking branch 'origin/dev' into ota_base_extract 2025-07-01 11:50:49 -05:00
J. Nick Koston
5f764fc019 fix 2025-07-01 11:39:34 -05:00
J. Nick Koston
fc5ab71772 Merge branch 'ota_base_extract' into ota_base_extract_bk 2025-07-01 11:29:51 -05:00
J. Nick Koston
825d0bed88 fix esp8266 error handling 2025-07-01 11:29:38 -05:00
J. Nick Koston
9632f0248e Merge branch 'bk7200_tagged_pointer_fix' into ota_base_extract_bk 2025-07-01 11:21:05 -05:00
J. Nick Koston
cd1390916c md5 fixes 2025-07-01 11:09:08 -05:00
J. Nick Koston
149bdaf146 fixes 2025-07-01 10:50:17 -05:00
J. Nick Koston
ad628c9cba single ota path 2025-07-01 10:36:36 -05:00
J. Nick Koston
b88f87799e single ota path 2025-07-01 10:30:52 -05:00
J. Nick Koston
1ff7cf1125 single ota path 2025-07-01 10:28:48 -05:00
J. Nick Koston
31db6e51eb single ota path 2025-07-01 10:27:46 -05:00
J. Nick Koston
681d9236f9 single ota path 2025-07-01 10:26:55 -05:00
J. Nick Koston
8aa8af735d single ota path 2025-07-01 10:25:48 -05:00
J. Nick Koston
943d0f103d single ota path 2025-07-01 10:17:28 -05:00
J. Nick Koston
8b195d7f63 use ota backend 2025-07-01 10:11:41 -05:00
J. Nick Koston
649ad47e62 web_server_ support for ota backend idf 2025-07-01 10:05:23 -05:00
J. Nick Koston
93dc5765bb Merge upstream/dev into ota_base_extract 2025-07-01 09:57:09 -05:00
J. Nick Koston
b000b1b70c Fix regression: BK7231N devices not returning entities via API 2025-07-01 09:43:50 -05:00
J. Nick Koston
560886eb90 clenaup 2025-06-30 13:32:59 -05:00
J. Nick Koston
340bb5cef6 clenaup 2025-06-30 13:31:55 -05:00
J. Nick Koston
44a7c1d4a5 cleanup 2025-06-30 13:14:55 -05:00
J. Nick Koston
519c49f175 Revert "fix"
This reverts commit c96ffefa42.
2025-06-30 13:11:27 -05:00
J. Nick Koston
c96ffefa42 fix 2025-06-30 13:02:26 -05:00
J. Nick Koston
490ca8ad5a relo 2025-06-30 12:53:41 -05:00
J. Nick Koston
e385f87d6c move more 2025-06-30 12:46:47 -05:00
J. Nick Koston
58de53123a move more 2025-06-30 12:41:55 -05:00
J. Nick Koston
4f365c1716 todo 2025-06-30 12:11:37 -05:00
J. Nick Koston
981177da23 todo 2025-06-30 12:09:07 -05:00
J. Nick Koston
088bea9ccd split 2025-06-30 10:50:26 -05:00
J. Nick Koston
36350f179e split 2025-06-30 10:49:59 -05:00
J. Nick Koston
902f08c1bc Extract OTA backend functionality into separate ota_base component 2025-06-30 10:38:31 -05:00
J. Nick Koston
47ad206ccd Extract OTA backend functionality into separate ota_base component 2025-06-30 10:35:19 -05:00
J. Nick Koston
9f51546023 Extract OTA backend functionality into separate ota_base component 2025-06-30 10:33:43 -05:00
28 changed files with 130 additions and 2032 deletions

View File

@@ -458,13 +458,6 @@ def command_vscode(args):
def command_compile(args, config):
# Set memory analysis options in config
if args.analyze_memory:
config.setdefault(CONF_ESPHOME, {})["analyze_memory"] = True
if args.memory_report:
config.setdefault(CONF_ESPHOME, {})["memory_report_file"] = args.memory_report
exit_code = write_cpp(config)
if exit_code != 0:
return exit_code
@@ -844,17 +837,6 @@ def parse_args(argv):
help="Only generate source code, do not compile.",
action="store_true",
)
parser_compile.add_argument(
"--analyze-memory",
help="Analyze and display memory usage by component after compilation.",
action="store_true",
)
parser_compile.add_argument(
"--memory-report",
help="Save memory analysis report to a file (supports .json or .txt).",
type=str,
metavar="FILE",
)
parser_upload = subparsers.add_parser(
"upload",

File diff suppressed because it is too large Load Diff

View File

@@ -517,7 +517,7 @@ class APIConnection : public APIServerConnection {
private:
// Helper to cleanup items from the beginning
void cleanup_items_(size_t count) {
void cleanup_items(size_t count) {
for (size_t i = 0; i < count; i++) {
items[i].creator.cleanup(items[i].message_type);
}
@@ -541,14 +541,14 @@ class APIConnection : public APIServerConnection {
// Clear all items with proper cleanup
void clear() {
cleanup_items_(items.size());
cleanup_items(items.size());
items.clear();
batch_start_time = 0;
}
// Remove processed items from the front with proper cleanup
void remove_front(size_t count) {
cleanup_items_(count);
cleanup_items(count);
items.erase(items.begin(), items.begin() + count);
}

View File

@@ -3,7 +3,6 @@
#include "api_pb2.h"
#include "api_pb2_size.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include <cinttypes>
@@ -3511,7 +3510,7 @@ void SubscribeLogsResponse::dump_to(std::string &out) const {
out.append("\n");
out.append(" message: ");
out.append(format_hex_pretty(this->message));
out.append("'").append(this->message).append("'");
out.append("\n");
out.append(" send_failed: ");
@@ -3539,7 +3538,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("'").append(this->key).append("'");
out.append("\n");
out.append("}");
}
@@ -4285,7 +4284,7 @@ void CameraImageResponse::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append(" done: ");
@@ -6812,7 +6811,7 @@ void BluetoothServiceData::dump_to(std::string &out) const {
}
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -6895,7 +6894,7 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
out.append("\n");
out.append(" name: ");
out.append(format_hex_pretty(this->name));
out.append("'").append(this->name).append("'");
out.append("\n");
out.append(" rssi: ");
@@ -6988,7 +6987,7 @@ void BluetoothLERawAdvertisement::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -7515,7 +7514,7 @@ void BluetoothGATTReadResponse::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -7579,7 +7578,7 @@ void BluetoothGATTWriteRequest::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -7671,7 +7670,7 @@ void BluetoothGATTWriteDescriptorRequest::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -7773,7 +7772,7 @@ void BluetoothGATTNotifyDataResponse::dump_to(std::string &out) const {
out.append("\n");
out.append(" data: ");
out.append(format_hex_pretty(this->data));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append("}");
}
@@ -8493,7 +8492,7 @@ 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));
out.append("'").append(this->data).append("'");
out.append("\n");
out.append(" end: ");

View File

@@ -12,7 +12,7 @@ from esphome.const import (
)
from esphome.core import CORE, coroutine_with_priority
AUTO_LOAD = ["web_server_base", "ota.web_server"]
AUTO_LOAD = ["web_server_base"]
DEPENDENCIES = ["wifi"]
CODEOWNERS = ["@OttoWinter"]

View File

@@ -47,6 +47,9 @@ void CaptivePortal::start() {
this->base_->init();
if (!this->initialized_) {
this->base_->add_handler(this);
#ifdef USE_WEBSERVER_OTA
this->base_->add_ota_handler();
#endif
}
#ifdef USE_ARDUINO

View File

@@ -21,43 +21,6 @@ static const uint32_t RMT_CLK_FREQ = 80000000;
static const uint8_t RMT_CLK_DIV = 2;
#endif
static const size_t RMT_SYMBOLS_PER_BYTE = 8;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size_t symbols_written, size_t symbols_free,
rmt_symbol_word_t *symbols, bool *done, void *arg) {
auto *params = static_cast<LedParams *>(arg);
const auto *bytes = static_cast<const uint8_t *>(data);
size_t index = symbols_written / RMT_SYMBOLS_PER_BYTE;
// convert byte to symbols
if (index < size) {
if (symbols_free < RMT_SYMBOLS_PER_BYTE) {
return 0;
}
for (int32_t i = 0; i < RMT_SYMBOLS_PER_BYTE; i++) {
if (bytes[index] & (1 << (7 - i))) {
symbols[i] = params->bit1;
} else {
symbols[i] = params->bit0;
}
}
if ((index + 1) >= size && params->reset.duration0 == 0 && params->reset.duration1 == 0) {
*done = true;
}
return RMT_SYMBOLS_PER_BYTE;
}
// send reset
if (symbols_free < 1) {
return 0;
}
symbols[0] = params->reset;
*done = true;
return 1;
}
#endif
void ESP32RMTLEDStripLightOutput::setup() {
ESP_LOGCONFIG(TAG, "Running setup");
@@ -79,15 +42,10 @@ void ESP32RMTLEDStripLightOutput::setup() {
return;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
// copy of the led buffer
this->rmt_buf_ = allocator.allocate(buffer_size);
#else
RAMAllocator<rmt_symbol_word_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_symbol_word_t>::ALLOC_INTERNAL);
// 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1);
#endif
rmt_tx_channel_config_t channel;
memset(&channel, 0, sizeof(channel));
@@ -107,18 +65,6 @@ void ESP32RMTLEDStripLightOutput::setup() {
return;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
rmt_simple_encoder_config_t encoder;
memset(&encoder, 0, sizeof(encoder));
encoder.callback = encoder_callback;
encoder.arg = &this->params_;
encoder.min_chunk_size = 8;
if (rmt_new_simple_encoder(&encoder, &this->encoder_) != ESP_OK) {
ESP_LOGE(TAG, "Encoder creation failed");
this->mark_failed();
return;
}
#else
rmt_copy_encoder_config_t encoder;
memset(&encoder, 0, sizeof(encoder));
if (rmt_new_copy_encoder(&encoder, &this->encoder_) != ESP_OK) {
@@ -126,7 +72,6 @@ void ESP32RMTLEDStripLightOutput::setup() {
this->mark_failed();
return;
}
#endif
if (rmt_enable(this->channel_) != ESP_OK) {
ESP_LOGE(TAG, "Enabling channel failed");
@@ -140,20 +85,20 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f;
// 0-bit
this->params_.bit0.duration0 = (uint32_t) (ratio * bit0_high);
this->params_.bit0.level0 = 1;
this->params_.bit0.duration1 = (uint32_t) (ratio * bit0_low);
this->params_.bit0.level1 = 0;
this->bit0_.duration0 = (uint32_t) (ratio * bit0_high);
this->bit0_.level0 = 1;
this->bit0_.duration1 = (uint32_t) (ratio * bit0_low);
this->bit0_.level1 = 0;
// 1-bit
this->params_.bit1.duration0 = (uint32_t) (ratio * bit1_high);
this->params_.bit1.level0 = 1;
this->params_.bit1.duration1 = (uint32_t) (ratio * bit1_low);
this->params_.bit1.level1 = 0;
this->bit1_.duration0 = (uint32_t) (ratio * bit1_high);
this->bit1_.level0 = 1;
this->bit1_.duration1 = (uint32_t) (ratio * bit1_low);
this->bit1_.level1 = 0;
// reset
this->params_.reset.duration0 = (uint32_t) (ratio * reset_time_high);
this->params_.reset.level0 = 1;
this->params_.reset.duration1 = (uint32_t) (ratio * reset_time_low);
this->params_.reset.level1 = 0;
this->reset_.duration0 = (uint32_t) (ratio * reset_time_high);
this->reset_.level0 = 1;
this->reset_.duration1 = (uint32_t) (ratio * reset_time_low);
this->reset_.level1 = 0;
}
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
@@ -177,9 +122,6 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
}
delayMicroseconds(50);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
memcpy(this->rmt_buf_, this->buf_, this->get_buffer_size_());
#else
size_t buffer_size = this->get_buffer_size_();
size_t size = 0;
@@ -189,7 +131,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
while (size < buffer_size) {
uint8_t b = *psrc;
for (int i = 0; i < 8; i++) {
pdest->val = b & (1 << (7 - i)) ? this->params_.bit1.val : this->params_.bit0.val;
pdest->val = b & (1 << (7 - i)) ? this->bit1_.val : this->bit0_.val;
pdest++;
len++;
}
@@ -197,20 +139,17 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
psrc++;
}
if (this->params_.reset.duration0 > 0 || this->params_.reset.duration1 > 0) {
pdest->val = this->params_.reset.val;
if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) {
pdest->val = this->reset_.val;
pdest++;
len++;
}
#endif
rmt_transmit_config_t config;
memset(&config, 0, sizeof(config));
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config);
#else
config.loop_count = 0;
config.flags.eot_level = 0;
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config);
#endif
if (error != ESP_OK) {
ESP_LOGE(TAG, "RMT TX error");
this->status_set_warning();

View File

@@ -25,12 +25,6 @@ enum RGBOrder : uint8_t {
ORDER_BRG,
};
struct LedParams {
rmt_symbol_word_t bit0;
rmt_symbol_word_t bit1;
rmt_symbol_word_t reset;
};
class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
public:
void setup() override;
@@ -78,15 +72,12 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
uint8_t *buf_{nullptr};
uint8_t *effect_data_{nullptr};
LedParams params_;
rmt_channel_handle_t channel_{nullptr};
rmt_encoder_handle_t encoder_{nullptr};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
uint8_t *rmt_buf_{nullptr};
#else
rmt_symbol_word_t *rmt_buf_{nullptr};
#endif
rmt_symbol_word_t bit0_, bit1_, reset_;
uint32_t rmt_symbols_{48};
uint8_t pin_;
uint16_t num_leds_;
bool is_rgbw_{false};

View File

@@ -133,6 +133,7 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(std::string url, std:
std::string header_value = container->client_.header(i).c_str();
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
container->response_headers_[header_name].push_back(header_value);
break;
}
}

View File

@@ -42,6 +42,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
const std::string header_value = evt->header_value;
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
user_data->response_headers[header_name].push_back(header_value);
break;
}
break;
}

View File

@@ -39,7 +39,7 @@ void MMC5603Component::setup() {
return;
}
if (id != 0 && id != MMC56X3_CHIP_ID) { // ID is not reported correctly by all chips, 0 on some chips
if (id != MMC56X3_CHIP_ID) {
ESP_LOGCONFIG(TAG, "Chip Wrong");
this->error_code_ = ID_REGISTERS;
this->mark_failed();

View File

@@ -164,7 +164,7 @@ void Nextion::dump_config() {
#endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP
if (this->touch_sleep_timeout_ != 0) {
ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu16, this->touch_sleep_timeout_);
ESP_LOGCONFIG(TAG, " Touch Timeout: %" PRIu32, this->touch_sleep_timeout_);
}
if (this->wake_up_page_ != -1) {
@@ -302,11 +302,11 @@ void Nextion::loop() {
}
// Check if a startup page has been set and send the command
if (this->start_up_page_ >= 0) {
if (this->start_up_page_ != -1) {
this->goto_page(this->start_up_page_);
}
if (this->wake_up_page_ >= 0) {
if (this->wake_up_page_ != -1) {
this->set_wake_up_page(this->wake_up_page_);
}
@@ -418,12 +418,12 @@ void Nextion::process_nextion_commands_() {
ESP_LOGN(TAG, "Add 0xFF");
}
const uint8_t nextion_event = this->command_data_[0];
this->nextion_event_ = this->command_data_[0];
to_process_length -= 1;
to_process = this->command_data_.substr(1, to_process_length);
switch (nextion_event) {
switch (this->nextion_event_) {
case 0x00: // instruction sent by user has failed
ESP_LOGW(TAG, "Invalid instruction");
this->remove_from_q_();
@@ -562,9 +562,9 @@ void Nextion::process_nextion_commands_() {
break;
}
const uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1];
const uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3];
const uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press
uint16_t x = (uint16_t(to_process[0]) << 8) | to_process[1];
uint16_t y = (uint16_t(to_process[2]) << 8) | to_process[3];
uint8_t touch_event = to_process[4]; // 0 -> release, 1 -> press
ESP_LOGD(TAG, "Touch %s at %u,%u", touch_event ? "PRESS" : "RELEASE", x, y);
break;
}
@@ -820,14 +820,15 @@ void Nextion::process_nextion_commands_() {
break;
}
default:
ESP_LOGW(TAG, "Unknown event: 0x%02X", nextion_event);
ESP_LOGW(TAG, "Unknown event: 0x%02X", this->nextion_event_);
break;
}
// ESP_LOGN(TAG, "nextion_event_ deleting from 0 to %d", to_process_length + COMMAND_DELIMITER.length() + 1);
this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1);
}
const uint32_t ms = App.get_loop_component_start_time();
uint32_t ms = App.get_loop_component_start_time();
if (!this->nextion_queue_.empty() && this->nextion_queue_.front()->queue_time + this->max_q_age_ms_ < ms) {
for (size_t i = 0; i < this->nextion_queue_.size(); i++) {
@@ -959,6 +960,7 @@ void Nextion::update_components_by_prefix(const std::string &prefix) {
}
uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag) {
uint16_t ret = 0;
uint8_t c = 0;
uint8_t nr_of_ff_bytes = 0;
bool exit_flag = false;
@@ -1001,7 +1003,8 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool
if (ff_flag)
response = response.substr(0, response.length() - 3); // Remove last 3 0xFF
return response.length();
ret = response.length();
return ret;
}
/**

View File

@@ -1190,11 +1190,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
* After 30 seconds the display will go to sleep. Note: the display will only wakeup by a restart or by setting up
* `thup`.
*/
void set_touch_sleep_timeout(uint16_t touch_sleep_timeout);
void set_touch_sleep_timeout(uint32_t touch_sleep_timeout);
/**
* Sets which page Nextion loads when exiting sleep mode. Note this can be set even when Nextion is in sleep mode.
* @param wake_up_page The page id, from 0 to the last page in Nextion. Set -1 (not set to any existing page) to
* @param wake_up_page The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to
* wakes up to current page.
*
* Example:
@@ -1204,11 +1204,11 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
*
* The display will wake up to page 2.
*/
void set_wake_up_page(int16_t wake_up_page = -1);
void set_wake_up_page(uint8_t wake_up_page = 255);
/**
* Sets which page Nextion loads when connecting to ESPHome.
* @param start_up_page The page id, from 0 to the last page in Nextion. Set -1 (not set to any existing page) to
* @param start_up_page The page id, from 0 to the lage page in Nextion. Set 255 (not set to any existing page) to
* wakes up to current page.
*
* Example:
@@ -1218,7 +1218,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
*
* The display will go to page 2 when it establishes a connection to ESPHome.
*/
void set_start_up_page(int16_t start_up_page = -1) { this->start_up_page_ = start_up_page; }
void set_start_up_page(uint8_t start_up_page = 255) { this->start_up_page_ = start_up_page; }
/**
* Sets if Nextion should auto-wake from sleep when touch press occurs.
@@ -1330,7 +1330,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
std::deque<NextionQueue *> waveform_queue_;
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag);
void all_components_send_state_(bool force_update = false);
uint32_t comok_sent_ = 0;
uint64_t comok_sent_ = 0;
bool remove_from_q_(bool report_empty = true);
/**
@@ -1340,10 +1340,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
bool ignore_is_setup_ = false;
bool nextion_reports_is_setup_ = false;
uint8_t nextion_event_;
void process_nextion_commands_();
void process_serial_();
bool is_updating_ = false;
uint16_t touch_sleep_timeout_ = 0;
uint32_t touch_sleep_timeout_ = 0;
int16_t wake_up_page_ = -1;
int16_t start_up_page_ = -1;
bool auto_wake_on_touch_ = true;

View File

@@ -10,12 +10,12 @@ static const char *const TAG = "nextion";
// Sleep safe commands
void Nextion::soft_reset() { this->send_command_("rest"); }
void Nextion::set_wake_up_page(int16_t wake_up_page) {
void Nextion::set_wake_up_page(uint8_t wake_up_page) {
this->wake_up_page_ = wake_up_page;
this->add_no_result_to_queue_with_set_internal_("wake_up_page", "wup", wake_up_page, true);
}
void Nextion::set_touch_sleep_timeout(uint16_t touch_sleep_timeout) {
void Nextion::set_touch_sleep_timeout(uint32_t touch_sleep_timeout) {
if (touch_sleep_timeout < 3) {
ESP_LOGD(TAG, "Sleep timeout out of bounds (3-65535)");
return;

View File

@@ -31,10 +31,6 @@ void PulseMeterSensor::setup() {
this->pulse_state_.latched_ = this->last_pin_val_;
this->pin_->attach_interrupt(PulseMeterSensor::pulse_intr, this, gpio::INTERRUPT_ANY_EDGE);
}
if (this->total_sensor_ != nullptr) {
this->total_sensor_->publish_state(this->total_pulses_);
}
}
void PulseMeterSensor::loop() {

View File

@@ -21,24 +21,21 @@ ECC = {
"HIGH": qrcodegen_Ecc.qrcodegen_Ecc_HIGH,
}
CONFIG_SCHEMA = cv.ensure_list(
cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(QRCode),
cv.Required(CONF_VALUE): cv.string,
cv.Optional(CONF_ECC, default="LOW"): cv.enum(ECC, upper=True),
}
)
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.declare_id(QRCode),
cv.Required(CONF_VALUE): cv.string,
cv.Optional(CONF_ECC, default="LOW"): cv.enum(ECC, upper=True),
}
)
async def to_code(config):
cg.add_library("wjtje/qr-code-generator-library", "^1.7.0")
for entry in config:
var = cg.new_Pvariable(entry[CONF_ID])
cg.add(var.set_value(entry[CONF_VALUE]))
cg.add(var.set_ecc(ECC[entry[CONF_ECC]]))
await cg.register_component(var, entry)
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_value(config[CONF_VALUE]))
cg.add(var.set_ecc(ECC[config[CONF_ECC]]))
await cg.register_component(var, config)
cg.add_define("USE_QR_CODE")

View File

@@ -1,9 +1,8 @@
import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import CORE, coroutine_with_priority
from esphome.core import coroutine_with_priority
CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network", "web_server_base"]
@@ -28,5 +27,3 @@ async def to_code(config):
await ota_to_code(var, config)
await cg.register_component(var, config)
cg.add_define("USE_WEBSERVER_OTA")
if CORE.using_esp_idf:
add_idf_component(name="zorxx/multipart-parser", ref="1.0.1")

View File

@@ -5,14 +5,6 @@
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#ifdef USE_ARDUINO
#ifdef USE_ESP8266
#include <Updater.h>
#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
#include <Update.h>
#endif
#endif // USE_ARDUINO
namespace esphome {
namespace web_server {
@@ -99,7 +91,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
#ifdef USE_ESP8266
Update.runAsync(true);
#endif
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_LIBRETINY)
if (Update.isRunning()) {
Update.abort();
}
@@ -189,12 +181,11 @@ void WebServerOTAComponent::setup() {
// Get the global web server base instance and register our handler
auto *base = web_server_base::global_web_server_base;
if (base == nullptr) {
ESP_LOGE(TAG, "WebServerBase not found");
ESP_LOGE(TAG, "WebServerBase not found. WebServer OTA requires web_server_base component");
this->mark_failed();
return;
}
// AsyncWebServer takes ownership of the handler and will delete it when the server is destroyed
base->add_handler(new OTARequestHandler(this)); // NOLINT
#ifdef USE_OTA_STATE_CALLBACK
// Register with global OTA callback system

View File

@@ -40,4 +40,7 @@ async def to_code(config):
if CORE.is_esp8266:
cg.add_library("ESP8266WiFi", None)
# https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.8")
# Use fork with libretiny compatibility fix
cg.add_library(
"https://github.com/bdraco/ESPAsyncWebServer.git#libretiny_Fix", None
)

View File

@@ -1,5 +1,7 @@
from esphome.components.esp32 import add_idf_sdkconfig_option
from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option
import esphome.config_validation as cv
from esphome.const import CONF_OTA
from esphome.core import CORE
CODEOWNERS = ["@dentra"]
@@ -12,3 +14,12 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
# Increase the maximum supported size of headers section in HTTP request packet to be processed by the server
add_idf_sdkconfig_option("CONFIG_HTTPD_MAX_REQ_HDR_LEN", 1024)
# Check if web_server OTA platform is configured
ota_config = CORE.config.get(CONF_OTA, [])
has_web_server_ota = any(
platform.get("platform") == "web_server" for platform in ota_config
)
if has_web_server_ota:
# Add multipart parser dependency for web server OTA
add_idf_component(name="zorxx/multipart-parser", ref="1.0.1")

View File

@@ -67,42 +67,6 @@ ConfigPath = list[str | int]
path_context = contextvars.ContextVar("Config path")
def _process_platform_config(
result: Config,
component_name: str,
platform_name: str,
platform_config: ConfigType,
path: ConfigPath,
) -> None:
"""Process a platform configuration and add necessary validation steps.
This is shared between LoadValidationStep and AutoLoadValidationStep to avoid duplication.
"""
# Get the platform manifest
platform = get_platform(component_name, platform_name)
if platform is None:
result.add_str_error(
f"Platform not found: '{component_name}.{platform_name}'", path
)
return
# Add platform to loaded integrations
CORE.loaded_integrations.add(platform_name)
CORE.loaded_platforms.add(f"{component_name}/{platform_name}")
# Process platform's AUTO_LOAD
for load in platform.auto_load:
if load not in result:
result.add_validation_step(AutoLoadValidationStep(load))
# Add validation steps for the platform
p_domain = f"{component_name}.{platform_name}"
result.add_output_path(path, p_domain)
result.add_validation_step(
MetadataValidationStep(path, p_domain, platform_config, platform)
)
def _path_begins_with(path: ConfigPath, other: ConfigPath) -> bool:
if len(path) < len(other):
return False
@@ -415,11 +379,26 @@ class LoadValidationStep(ConfigValidationStep):
path,
)
continue
# Remove temp output path
# Remove temp output path and construct new one
result.remove_output_path(path, p_domain)
p_domain = f"{self.domain}.{p_name}"
result.add_output_path(path, p_domain)
# Try Load platform
platform = get_platform(self.domain, p_name)
if platform is None:
result.add_str_error(f"Platform not found: '{p_domain}'", path)
continue
CORE.loaded_integrations.add(p_name)
CORE.loaded_platforms.add(f"{self.domain}/{p_name}")
# Process the platform configuration
_process_platform_config(result, self.domain, p_name, p_config, path)
# Process AUTO_LOAD
for load in platform.auto_load:
if load not in result:
result.add_validation_step(AutoLoadValidationStep(load))
result.add_validation_step(
MetadataValidationStep(path, p_domain, p_config, platform)
)
class AutoLoadValidationStep(ConfigValidationStep):
@@ -434,56 +413,10 @@ class AutoLoadValidationStep(ConfigValidationStep):
self.domain = domain
def run(self, result: Config) -> None:
# Regular component auto-load (no platform)
if "." not in self.domain:
if self.domain in result:
# already loaded
return
result.add_validation_step(LoadValidationStep(self.domain, core.AutoLoad()))
if self.domain in result:
# already loaded
return
# Platform-specific auto-load (e.g., "ota.web_server")
component_name, _, platform_name = self.domain.partition(".")
# Check if component exists
if component_name not in result:
# Component doesn't exist, load it first
result.add_validation_step(LoadValidationStep(component_name, []))
# Re-run this step after the component is loaded
result.add_validation_step(AutoLoadValidationStep(self.domain))
return
# Component exists, check if it's a platform component
component = get_component(component_name)
if component is None or not component.is_platform_component:
result.add_str_error(
f"Component {component_name} is not a platform component, "
f"cannot auto-load platform {platform_name}",
[component_name],
)
return
# Ensure the component config is a list
component_conf = result.get(component_name)
if not isinstance(component_conf, list):
component_conf = result[component_name] = []
# Check if platform already exists
if any(
isinstance(conf, dict) and conf.get(CONF_PLATFORM) == platform_name
for conf in component_conf
):
return
# Add and process the platform configuration
platform_conf = core.AutoLoad()
platform_conf[CONF_PLATFORM] = platform_name
component_conf.append(platform_conf)
path = [component_name, len(component_conf) - 1]
_process_platform_config(
result, component_name, platform_name, platform_conf, path
)
result.add_validation_step(LoadValidationStep(self.domain, core.AutoLoad()))
class MetadataValidationStep(ConfigValidationStep):

View File

@@ -84,10 +84,6 @@ void Application::setup() {
}
ESP_LOGI(TAG, "setup() finished successfully!");
// Clear setup priority overrides to free memory
clear_setup_priority_overrides();
this->schedule_dump_config();
this->calculate_looping_components_();
}

View File

@@ -2,9 +2,7 @@
#include <cinttypes>
#include <limits>
#include <memory>
#include <utility>
#include <vector>
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
@@ -14,30 +12,6 @@ namespace esphome {
static const char *const TAG = "component";
// Global vectors for component data that doesn't belong in every instance.
// Using vector instead of unordered_map for both because:
// - Much lower memory overhead (8 bytes per entry vs 20+ for unordered_map)
// - Linear search is fine for small n (typically < 5 entries)
// - These are rarely accessed (setup only or error cases only)
// Component error messages - only stores messages for failed components
// Lazy allocated since most configs have zero failures
// Note: We don't clear this vector because:
// 1. Components are never destroyed in ESPHome
// 2. Failed components remain failed (no recovery mechanism)
// 3. Memory usage is minimal (only failures with custom messages are stored)
static std::unique_ptr<std::vector<std::pair<const Component *, const char *>>> &get_component_error_messages() {
static std::unique_ptr<std::vector<std::pair<const Component *, const char *>>> instance;
return instance;
}
// Setup priority overrides - freed after setup completes
// Typically < 5 entries, lazy allocated
static std::unique_ptr<std::vector<std::pair<const Component *, float>>> &get_setup_priority_overrides() {
static std::unique_ptr<std::vector<std::pair<const Component *, float>>> instance;
return instance;
}
namespace setup_priority {
const float BUS = 1000.0f;
@@ -128,17 +102,8 @@ void Component::call_setup() { this->setup(); }
void Component::call_dump_config() {
this->dump_config();
if (this->is_failed()) {
// Look up error message from global vector
const char *error_msg = "unspecified";
if (get_component_error_messages()) {
for (const auto &pair : *get_component_error_messages()) {
if (pair.first == this) {
error_msg = pair.second;
break;
}
}
}
ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(), error_msg);
ESP_LOGE(TAG, " Component %s is marked FAILED: %s", this->get_component_source(),
this->error_message_ ? this->error_message_ : "unspecified");
}
}
@@ -280,21 +245,8 @@ void Component::status_set_error(const char *message) {
this->component_state_ |= STATUS_LED_ERROR;
App.app_state_ |= STATUS_LED_ERROR;
ESP_LOGE(TAG, "Component %s set Error flag: %s", this->get_component_source(), message);
if (strcmp(message, "unspecified") != 0) {
// Lazy allocate the error messages vector if needed
if (!get_component_error_messages()) {
get_component_error_messages() = std::make_unique<std::vector<std::pair<const Component *, const char *>>>();
}
// Check if this component already has an error message
for (auto &pair : *get_component_error_messages()) {
if (pair.first == this) {
pair.second = message;
return;
}
}
// Add new error message
get_component_error_messages()->emplace_back(this, message);
}
if (strcmp(message, "unspecified") != 0)
this->error_message_ = message;
}
void Component::status_clear_warning() {
if ((this->component_state_ & STATUS_LED_WARNING) == 0)
@@ -318,36 +270,11 @@ void Component::status_momentary_error(const std::string &name, uint32_t length)
}
void Component::dump_config() {}
float Component::get_actual_setup_priority() const {
// Check if there's an override in the global vector
if (get_setup_priority_overrides()) {
// Linear search is fine for small n (typically < 5 overrides)
for (const auto &pair : *get_setup_priority_overrides()) {
if (pair.first == this) {
return pair.second;
}
}
}
return this->get_setup_priority();
}
void Component::set_setup_priority(float priority) {
// Lazy allocate the vector if needed
if (!get_setup_priority_overrides()) {
get_setup_priority_overrides() = std::make_unique<std::vector<std::pair<const Component *, float>>>();
// Reserve some space to avoid reallocations (most configs have < 10 overrides)
get_setup_priority_overrides()->reserve(10);
}
// Check if this component already has an override
for (auto &pair : *get_setup_priority_overrides()) {
if (pair.first == this) {
pair.second = priority;
return;
}
}
// Add new override
get_setup_priority_overrides()->emplace_back(this, priority);
if (std::isnan(this->setup_priority_override_))
return this->get_setup_priority();
return this->setup_priority_override_;
}
void Component::set_setup_priority(float priority) { this->setup_priority_override_ = priority; }
bool Component::has_overridden_loop() const {
#if defined(USE_HOST) || defined(CLANG_TIDY)
@@ -409,9 +336,4 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() {}
void clear_setup_priority_overrides() {
// Free the setup priority map completely
get_setup_priority_overrides().reset();
}
} // namespace esphome

View File

@@ -387,7 +387,9 @@ class Component {
bool cancel_defer(const std::string &name); // NOLINT
// Ordered for optimal packing on 32-bit systems
float setup_priority_override_{NAN};
const char *component_source_{nullptr};
const char *error_message_{nullptr};
uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)
/// State of this component - each bit has a purpose:
/// Bits 0-1: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED)
@@ -457,7 +459,4 @@ class WarnIfComponentBlockingGuard {
Component *component_;
};
// Function to clear setup priority overrides after all components are set up
void clear_setup_priority_overrides();
} // namespace esphome

View File

@@ -4,13 +4,13 @@
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include <strings.h>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <strings.h>
#ifdef USE_HOST
#ifndef _WIN32
@@ -43,10 +43,10 @@
#include <random>
#endif
#ifdef USE_ESP32
#include "rom/crc.h"
#include "esp_mac.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_mac.h"
#include "rom/crc.h"
#endif
#ifdef USE_LIBRETINY
@@ -393,21 +393,6 @@ std::string format_hex_pretty(const uint16_t *data, size_t length) {
return ret;
}
std::string format_hex_pretty(const std::vector<uint16_t> &data) { return format_hex_pretty(data.data(), data.size()); }
std::string format_hex_pretty(const std::string &data) {
if (data.empty())
return "";
std::string ret;
ret.resize(3 * data.length() - 1);
for (size_t i = 0; i < data.length(); i++) {
ret[3 * i] = format_hex_pretty_char((data[i] & 0xF0) >> 4);
ret[3 * i + 1] = format_hex_pretty_char(data[i] & 0x0F);
if (i != data.length() - 1)
ret[3 * i + 2] = '.';
}
if (data.length() > 4)
return ret + " (" + std::to_string(data.length()) + ")";
return ret;
}
std::string format_bin(const uint8_t *data, size_t length) {
std::string result;

View File

@@ -348,8 +348,6 @@ std::string format_hex_pretty(const uint16_t *data, size_t length);
std::string format_hex_pretty(const std::vector<uint8_t> &data);
/// Format the vector \p data in pretty-printed, human-readable hex.
std::string format_hex_pretty(const std::vector<uint16_t> &data);
/// Format the string \p data in pretty-printed, human-readable hex.
std::string format_hex_pretty(const std::string &data);
/// Format an unsigned integer in pretty-printed, human-readable hex, starting with the most significant byte.
template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_hex_pretty(T val) {
val = convert_big_endian(val);

View File

@@ -5,7 +5,6 @@ import os
from pathlib import Path
import re
import subprocess
from typing import Any
from esphome.const import CONF_COMPILE_PROCESS_LIMIT, CONF_ESPHOME, KEY_CORE
from esphome.core import CORE, EsphomeError
@@ -105,16 +104,7 @@ def run_compile(config, verbose):
args = []
if CONF_COMPILE_PROCESS_LIMIT in config[CONF_ESPHOME]:
args += [f"-j{config[CONF_ESPHOME][CONF_COMPILE_PROCESS_LIMIT]}"]
result = run_platformio_cli_run(config, verbose, *args)
# Run memory analysis if enabled
if config.get(CONF_ESPHOME, {}).get("analyze_memory", False):
try:
analyze_memory_usage(config)
except Exception as e:
_LOGGER.warning("Failed to analyze memory usage: %s", e)
return result
return run_platformio_cli_run(config, verbose, *args)
def _run_idedata(config):
@@ -341,93 +331,3 @@ class IDEData:
return f"{self.cc_path[:-7]}addr2line.exe"
return f"{self.cc_path[:-3]}addr2line"
@property
def objdump_path(self) -> str:
# replace gcc at end with objdump
# Windows
if self.cc_path.endswith(".exe"):
return f"{self.cc_path[:-7]}objdump.exe"
return f"{self.cc_path[:-3]}objdump"
@property
def readelf_path(self) -> str:
# replace gcc at end with readelf
# Windows
if self.cc_path.endswith(".exe"):
return f"{self.cc_path[:-7]}readelf.exe"
return f"{self.cc_path[:-3]}readelf"
def analyze_memory_usage(config: dict[str, Any]) -> None:
"""Analyze memory usage by component after compilation."""
# Lazy import to avoid overhead when not needed
from esphome.analyze_memory import MemoryAnalyzer
idedata = get_idedata(config)
# Get paths to tools
elf_path = idedata.firmware_elf_path
objdump_path = idedata.objdump_path
readelf_path = idedata.readelf_path
# Debug logging
_LOGGER.debug("ELF path from idedata: %s", elf_path)
# Check if file exists
if not Path(elf_path).exists():
# Try alternate path
alt_path = Path(CORE.relative_build_path(".pioenvs", CORE.name, "firmware.elf"))
if alt_path.exists():
elf_path = str(alt_path)
_LOGGER.debug("Using alternate ELF path: %s", elf_path)
else:
_LOGGER.warning("ELF file not found at %s or %s", elf_path, alt_path)
return
# Extract external components from config
external_components = set()
# Get the list of built-in ESPHome components
from esphome.analyze_memory import get_esphome_components
builtin_components = get_esphome_components()
# Special non-component keys that appear in configs
NON_COMPONENT_KEYS = {
CONF_ESPHOME,
"substitutions",
"packages",
"globals",
"<<",
}
# Check all top-level keys in config
for key in config:
if key not in builtin_components and key not in NON_COMPONENT_KEYS:
# This is an external component
external_components.add(key)
_LOGGER.debug("Detected external components: %s", external_components)
# Create analyzer and run analysis
analyzer = MemoryAnalyzer(elf_path, objdump_path, readelf_path, external_components)
analyzer.analyze()
# Generate and print report
report = analyzer.generate_report()
_LOGGER.info("\n%s", report)
# Optionally save to file
if config.get(CONF_ESPHOME, {}).get("memory_report_file"):
report_file = Path(config[CONF_ESPHOME]["memory_report_file"])
if report_file.suffix == ".json":
report_file.write_text(analyzer.to_json())
_LOGGER.info("Memory report saved to %s", report_file)
else:
report_file.write_text(report)
_LOGGER.info("Memory report saved to %s", report_file)

View File

@@ -530,7 +530,7 @@ class BytesType(TypeInfo):
wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2
def dump(self, name: str) -> str:
o = f"out.append(format_hex_pretty({name}));"
o = f'out.append("\'").append({name}).append("\'");'
return o
def get_size_calculation(self, name: str, force: bool = False) -> str:
@@ -1255,7 +1255,6 @@ def main() -> None:
#include "api_pb2.h"
#include "api_pb2_size.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include <cinttypes>