Compare commits
63 Commits
memory
...
ota_base_e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cccbd7797 | ||
|
|
e920ffbef3 | ||
|
|
31b5a9a127 | ||
|
|
6395567f2a | ||
|
|
c8e7a945ae | ||
|
|
f2b5a8e3b1 | ||
|
|
0a836c7001 | ||
|
|
69819cdcc5 | ||
|
|
1756017181 | ||
|
|
11b5b00cd6 | ||
|
|
2c349cad8b | ||
|
|
08f563167f | ||
|
|
8713945c6a | ||
|
|
e7e6b7f89b | ||
|
|
4ec8cd9611 | ||
|
|
b89c5751b1 | ||
|
|
9d1e68e45d | ||
|
|
bc0a248149 | ||
|
|
ec99692963 | ||
|
|
77f7816114 | ||
|
|
f3e7a6887b | ||
|
|
401523c854 | ||
|
|
5b0c249272 | ||
|
|
3f650b2c15 | ||
|
|
a1e3b67683 | ||
|
|
6e45b9d2dd | ||
|
|
c008e6aa1c | ||
|
|
9799a2b636 | ||
|
|
099474053e | ||
|
|
efafabed97 | ||
|
|
2d0c109dc1 | ||
|
|
5f764fc019 | ||
|
|
fc5ab71772 | ||
|
|
825d0bed88 | ||
|
|
9632f0248e | ||
|
|
cd1390916c | ||
|
|
149bdaf146 | ||
|
|
ad628c9cba | ||
|
|
b88f87799e | ||
|
|
1ff7cf1125 | ||
|
|
31db6e51eb | ||
|
|
681d9236f9 | ||
|
|
8aa8af735d | ||
|
|
943d0f103d | ||
|
|
8b195d7f63 | ||
|
|
649ad47e62 | ||
|
|
93dc5765bb | ||
|
|
b000b1b70c | ||
|
|
560886eb90 | ||
|
|
340bb5cef6 | ||
|
|
44a7c1d4a5 | ||
|
|
519c49f175 | ||
|
|
c96ffefa42 | ||
|
|
490ca8ad5a | ||
|
|
e385f87d6c | ||
|
|
58de53123a | ||
|
|
4f365c1716 | ||
|
|
981177da23 | ||
|
|
088bea9ccd | ||
|
|
36350f179e | ||
|
|
902f08c1bc | ||
|
|
47ad206ccd | ||
|
|
9f51546023 |
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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: ");
|
||||
|
||||
@@ -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"]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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_();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user