diff --git a/esphome/components/libretiny/preferences.cpp b/esphome/components/libretiny/preferences.cpp index 871b186d8e..c21c5813a8 100644 --- a/esphome/components/libretiny/preferences.cpp +++ b/esphome/components/libretiny/preferences.cpp @@ -4,24 +4,27 @@ #include "esphome/core/log.h" #include "esphome/core/preferences.h" #include +#include #include #include -#include namespace esphome { namespace libretiny { static const char *const TAG = "lt.preferences"; +// Buffer size for converting uint32_t to string: max "4294967295" (10 chars) + null terminator + 1 padding +static constexpr size_t KEY_BUFFER_SIZE = 12; + struct NVSData { - std::string key; + uint32_t key; std::unique_ptr data; size_t len; void set_data(const uint8_t *src, size_t size) { - data = std::make_unique(size); - memcpy(data.get(), src, size); - len = size; + this->data = std::make_unique(size); + memcpy(this->data.get(), src, size); + this->len = size; } }; @@ -29,30 +32,30 @@ static std::vector s_pending_save; // NOLINT(cppcoreguidelines-avoid-n class LibreTinyPreferenceBackend : public ESPPreferenceBackend { public: - std::string key; + uint32_t key; fdb_kvdb_t db; fdb_blob_t blob; bool save(const uint8_t *data, size_t len) override { // try find in pending saves and update that for (auto &obj : s_pending_save) { - if (obj.key == key) { + if (obj.key == this->key) { obj.set_data(data, len); return true; } } NVSData save{}; - save.key = key; + save.key = this->key; save.set_data(data, len); s_pending_save.emplace_back(std::move(save)); - ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %zu", key.c_str(), len); + ESP_LOGVV(TAG, "s_pending_save: key: %" PRIu32 ", len: %zu", this->key, len); return true; } bool load(uint8_t *data, size_t len) override { // try find in pending saves and load from that for (auto &obj : s_pending_save) { - if (obj.key == key) { + if (obj.key == this->key) { if (obj.len != len) { // size mismatch return false; @@ -62,13 +65,15 @@ class LibreTinyPreferenceBackend : public ESPPreferenceBackend { } } - fdb_blob_make(blob, data, len); - size_t actual_len = fdb_kv_get_blob(db, key.c_str(), blob); + char key_str[KEY_BUFFER_SIZE]; + snprintf(key_str, sizeof(key_str), "%" PRIu32, this->key); + fdb_blob_make(this->blob, data, len); + size_t actual_len = fdb_kv_get_blob(this->db, key_str, this->blob); if (actual_len != len) { ESP_LOGVV(TAG, "NVS length does not match (%zu!=%zu)", actual_len, len); return false; } else { - ESP_LOGVV(TAG, "fdb_kv_get_blob: key: %s, len: %zu", key.c_str(), len); + ESP_LOGVV(TAG, "fdb_kv_get_blob: key: %s, len: %zu", key_str, len); } return true; } @@ -90,16 +95,14 @@ class LibreTinyPreferences : public ESPPreferences { } ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { - return make_preference(length, type); + return this->make_preference(length, type); } ESPPreferenceObject make_preference(size_t length, uint32_t type) override { auto *pref = new LibreTinyPreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory) - pref->db = &db; - pref->blob = &blob; - - uint32_t keyval = type; - pref->key = str_sprintf("%u", keyval); + pref->db = &this->db; + pref->blob = &this->blob; + pref->key = type; return ESPPreferenceObject(pref); } @@ -112,18 +115,20 @@ class LibreTinyPreferences : public ESPPreferences { // goal try write all pending saves even if one fails int cached = 0, written = 0, failed = 0; fdb_err_t last_err = FDB_NO_ERR; - std::string last_key{}; + uint32_t last_key = 0; // go through vector from back to front (makes erase easier/more efficient) for (ssize_t i = s_pending_save.size() - 1; i >= 0; i--) { const auto &save = s_pending_save[i]; - ESP_LOGVV(TAG, "Checking if FDB data %s has changed", save.key.c_str()); - if (is_changed(&db, save)) { - ESP_LOGV(TAG, "sync: key: %s, len: %zu", save.key.c_str(), save.len); - fdb_blob_make(&blob, save.data.get(), save.len); - fdb_err_t err = fdb_kv_set_blob(&db, save.key.c_str(), &blob); + ESP_LOGVV(TAG, "Checking if FDB data %" PRIu32 " has changed", save.key); + if (this->is_changed(&this->db, save)) { + char key_str[KEY_BUFFER_SIZE]; + snprintf(key_str, sizeof(key_str), "%" PRIu32, save.key); + ESP_LOGV(TAG, "sync: key: %s, len: %zu", key_str, save.len); + fdb_blob_make(&this->blob, save.data.get(), save.len); + fdb_err_t err = fdb_kv_set_blob(&this->db, key_str, &this->blob); if (err != FDB_NO_ERR) { - ESP_LOGV(TAG, "fdb_kv_set_blob('%s', len=%zu) failed: %d", save.key.c_str(), save.len, err); + ESP_LOGV(TAG, "fdb_kv_set_blob('%s', len=%zu) failed: %d", key_str, save.len, err); failed++; last_err = err; last_key = save.key; @@ -131,7 +136,7 @@ class LibreTinyPreferences : public ESPPreferences { } written++; } else { - ESP_LOGD(TAG, "FDB data not changed; skipping %s len=%zu", save.key.c_str(), save.len); + ESP_LOGD(TAG, "FDB data not changed; skipping %" PRIu32 " len=%zu", save.key, save.len); cached++; } s_pending_save.erase(s_pending_save.begin() + i); @@ -139,17 +144,20 @@ class LibreTinyPreferences : public ESPPreferences { ESP_LOGD(TAG, "Writing %d items: %d cached, %d written, %d failed", cached + written + failed, cached, written, failed); if (failed > 0) { - ESP_LOGE(TAG, "Writing %d items failed. Last error=%d for key=%s", failed, last_err, last_key.c_str()); + ESP_LOGE(TAG, "Writing %d items failed. Last error=%d for key=%" PRIu32, failed, last_err, last_key); } return failed == 0; } bool is_changed(const fdb_kvdb_t db, const NVSData &to_save) { + char key_str[KEY_BUFFER_SIZE]; + snprintf(key_str, sizeof(key_str), "%" PRIu32, to_save.key); + struct fdb_kv kv; - fdb_kv_t kvp = fdb_kv_get_obj(db, to_save.key.c_str(), &kv); + fdb_kv_t kvp = fdb_kv_get_obj(db, key_str, &kv); if (kvp == nullptr) { - ESP_LOGV(TAG, "fdb_kv_get_obj('%s'): nullptr - the key might not be set yet", to_save.key.c_str()); + ESP_LOGV(TAG, "fdb_kv_get_obj('%s'): nullptr - the key might not be set yet", key_str); return true; } @@ -160,10 +168,10 @@ class LibreTinyPreferences : public ESPPreferences { // Allocate buffer on heap to avoid stack allocation for large data auto stored_data = std::make_unique(kv.value_len); - fdb_blob_make(&blob, stored_data.get(), kv.value_len); - size_t actual_len = fdb_kv_get_blob(db, to_save.key.c_str(), &blob); + fdb_blob_make(&this->blob, stored_data.get(), kv.value_len); + size_t actual_len = fdb_kv_get_blob(db, key_str, &this->blob); if (actual_len != kv.value_len) { - ESP_LOGV(TAG, "fdb_kv_get_blob('%s') len mismatch: %u != %u", to_save.key.c_str(), actual_len, kv.value_len); + ESP_LOGV(TAG, "fdb_kv_get_blob('%s') len mismatch: %u != %u", key_str, actual_len, kv.value_len); return true; } diff --git a/esphome/components/remote_base/abbwelcome_protocol.h b/esphome/components/remote_base/abbwelcome_protocol.h index 4b922eb2f1..b8d9293c11 100644 --- a/esphome/components/remote_base/abbwelcome_protocol.h +++ b/esphome/components/remote_base/abbwelcome_protocol.h @@ -232,10 +232,10 @@ template class ABBWelcomeAction : public RemoteTransmitterAction data.set_message_id(this->message_id_.value(x...)); data.auto_message_id = this->auto_message_id_.value(x...); std::vector data_vec; - if (this->len_ >= 0) { + if (this->len_ > 0) { // Static mode: copy from flash to vector data_vec.assign(this->data_.data, this->data_.data + this->len_); - } else { + } else if (this->len_ < 0) { // Template mode: call function data_vec = this->data_.func(x...); } @@ -245,7 +245,7 @@ template class ABBWelcomeAction : public RemoteTransmitterAction } protected: - ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length + ssize_t len_{0}; // <0 = template mode, >=0 = static mode with length union Data { std::vector (*func)(Ts...); // Function pointer (stateless lambdas) const uint8_t *data; // Pointer to static data in flash