[store_yaml] Address review: combined dump_config, encapsulate PROGMEM read

- Coalesce dump_config into a single ESP_LOGCONFIG call.
- Replace the raw get_data() accessor with a read_chunk() helper that copies
  bytes via progmem_read_byte, so callers cannot accidentally dereference the
  PROGMEM pointer directly on ESP8266.
- Update the API streaming handler to use read_chunk().
This commit is contained in:
J. Nick Koston
2026-05-15 10:20:04 -07:00
parent d0510364c9
commit 59e8242756
3 changed files with 27 additions and 11 deletions
+5 -6
View File
@@ -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);
+13 -4
View File
@@ -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
+9 -1
View File
@@ -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};