diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 811714c70ed..38d06be89bb 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1179,7 +1179,8 @@ static constexpr size_t STORE_YAML_CHUNK_SIZE = 512; static uint8_t store_yaml_chunk_buf[STORE_YAML_CHUNK_SIZE]; void APIConnection::on_get_yaml_request() { - if (store_yaml::global_store_yaml == nullptr || store_yaml::global_store_yaml->get_data() == nullptr) { + auto *comp = store_yaml::global_store_yaml; + if (comp == nullptr || comp->get_size() == 0) { // No blob — send a single done=true response so the client doesn't hang. GetYamlResponse resp; resp.done = true; @@ -1197,7 +1198,6 @@ void APIConnection::try_send_store_yaml_() { if (comp == nullptr) return; - const uint8_t *data = comp->get_data(); const size_t total = comp->get_size(); while (this->store_yaml_pos_ < total || this->store_yaml_pos_ == 0) { @@ -1207,10 +1207,9 @@ void APIConnection::try_send_store_yaml_() { const size_t remaining = total - this->store_yaml_pos_; const size_t to_send = remaining < STORE_YAML_CHUNK_SIZE ? remaining : STORE_YAML_CHUNK_SIZE; - // Copy from PROGMEM into a stack buffer. progmem_read_byte is a no-op except on ESP8266. - for (size_t i = 0; i < to_send; i++) { - store_yaml_chunk_buf[i] = progmem_read_byte(&data[this->store_yaml_pos_ + i]); - } + // Pulls a chunk out of PROGMEM into a stack buffer; on ESP8266 this routes + // through progmem_read_byte, on every other platform it's a plain byte copy. + comp->read_chunk(this->store_yaml_pos_, store_yaml_chunk_buf, to_send); GetYamlResponse resp; resp.set_data(store_yaml_chunk_buf, to_send); diff --git a/esphome/components/store_yaml/store_yaml.cpp b/esphome/components/store_yaml/store_yaml.cpp index 86b7a29f1c1..3a3e57c627e 100644 --- a/esphome/components/store_yaml/store_yaml.cpp +++ b/esphome/components/store_yaml/store_yaml.cpp @@ -14,10 +14,19 @@ StoreYamlComponent *global_store_yaml = nullptr; void StoreYamlComponent::setup() { global_store_yaml = this; } void StoreYamlComponent::dump_config() { - ESP_LOGCONFIG(TAG, "YAML:"); - ESP_LOGCONFIG(TAG, " Compressed size: %zu bytes", this->size_); - ESP_LOGCONFIG(TAG, " Uncompressed size: %zu bytes", this->uncompressed_size_); - ESP_LOGCONFIG(TAG, " Encoding: %s", ENCODING); + ESP_LOGCONFIG(TAG, + "YAML:\n" + " Compressed size: %zu bytes\n" + " Uncompressed size: %zu bytes\n" + " Encoding: %s", + this->size_, this->uncompressed_size_, ENCODING); +} + +void StoreYamlComponent::read_chunk(size_t pos, uint8_t *dst, size_t len) const { + const uint8_t *src = this->data_ + pos; + for (size_t i = 0; i < len; i++) { + dst[i] = progmem_read_byte(&src[i]); + } } } // namespace esphome::store_yaml diff --git a/esphome/components/store_yaml/store_yaml.h b/esphome/components/store_yaml/store_yaml.h index 6b0063264d1..61f3b87e728 100644 --- a/esphome/components/store_yaml/store_yaml.h +++ b/esphome/components/store_yaml/store_yaml.h @@ -23,11 +23,19 @@ class StoreYamlComponent : public Component { this->size_ = size; this->uncompressed_size_ = uncompressed_size; } - const uint8_t *get_data() const { return this->data_; } size_t get_size() const { return this->size_; } size_t get_uncompressed_size() const { return this->uncompressed_size_; } + // Copy `len` bytes from the PROGMEM blob at offset `pos` into `dst`. + // Hides the platform-specific read (no-op everywhere except ESP8266, where the + // blob lives in code space and must be read through `progmem_read_byte`). + void read_chunk(size_t pos, uint8_t *dst, size_t len) const; + protected: + // Points to a `const uint8_t[] PROGMEM` array emitted by codegen. On ESP8266 this + // address is in instruction flash and must be accessed via `progmem_read_byte` — + // hence the `read_chunk` accessor above. There is no public getter for the raw + // pointer; callers must go through `read_chunk`. const uint8_t *data_{nullptr}; size_t size_{0}; size_t uncompressed_size_{0};