14 static const char *
const TAG =
"lt.preferences";
18 std::vector<uint8_t> data;
21 static std::vector<NVSData> s_pending_save;
23 class LibreTinyPreferenceBackend :
public ESPPreferenceBackend {
29 bool save(
const uint8_t *data,
size_t len)
override {
31 for (
auto &obj : s_pending_save) {
33 obj.data.assign(data, data + len);
39 save.data.assign(data, data + len);
40 s_pending_save.emplace_back(save);
41 ESP_LOGVV(TAG,
"s_pending_save: key: %s, len: %d", key.c_str(),
len);
45 bool load(uint8_t *data,
size_t len)
override {
47 for (
auto &obj : s_pending_save) {
49 if (obj.data.size() !=
len) {
53 memcpy(data, obj.data.data(),
len);
58 fdb_blob_make(blob, data, len);
59 size_t actual_len = fdb_kv_get_blob(db, key.c_str(), blob);
60 if (actual_len != len) {
61 ESP_LOGVV(TAG,
"NVS length does not match (%u!=%u)", actual_len, len);
64 ESP_LOGVV(TAG,
"fdb_kv_get_blob: key: %s, len: %d", key.c_str(),
len);
70 class LibreTinyPreferences :
public ESPPreferences {
77 fdb_err_t err = fdb_kvdb_init(&db,
"esphome",
"kvs", NULL, NULL);
78 if (err != FDB_NO_ERR) {
79 LT_E(
"fdb_kvdb_init(...) failed: %d", err);
81 LT_I(
"Preferences initialized");
85 ESPPreferenceObject make_preference(
size_t length, uint32_t
type,
bool in_flash)
override {
86 return make_preference(length, type);
89 ESPPreferenceObject make_preference(
size_t length, uint32_t
type)
override {
90 auto *pref =
new LibreTinyPreferenceBackend();
94 uint32_t keyval =
type;
97 return ESPPreferenceObject(pref);
100 bool sync()
override {
101 if (s_pending_save.empty())
104 ESP_LOGD(TAG,
"Saving %d preferences to flash...", s_pending_save.size());
106 int cached = 0, written = 0, failed = 0;
107 fdb_err_t last_err = FDB_NO_ERR;
108 std::string last_key{};
111 for (ssize_t i = s_pending_save.size() - 1; i >= 0; i--) {
112 const auto &save = s_pending_save[i];
113 ESP_LOGVV(TAG,
"Checking if FDB data %s has changed", save.key.c_str());
114 if (is_changed(&db, save)) {
115 ESP_LOGV(TAG,
"sync: key: %s, len: %d", save.key.c_str(), save.data.size());
116 fdb_blob_make(&blob, save.data.data(), save.data.size());
117 fdb_err_t err = fdb_kv_set_blob(&db, save.key.c_str(), &blob);
118 if (err != FDB_NO_ERR) {
119 ESP_LOGV(TAG,
"fdb_kv_set_blob('%s', len=%u) failed: %d", save.key.c_str(), save.data.size(), err);
127 ESP_LOGD(TAG,
"FDB data not changed; skipping %s len=%u", save.key.c_str(), save.data.size());
130 s_pending_save.erase(s_pending_save.begin() + i);
132 ESP_LOGD(TAG,
"Saving %d preferences to flash: %d cached, %d written, %d failed", cached + written + failed, cached,
135 ESP_LOGE(TAG,
"Error saving %d preferences to flash. Last error=%d for key=%s", failed, last_err,
142 bool is_changed(
const fdb_kvdb_t db,
const NVSData &to_save) {
143 NVSData stored_data{};
145 fdb_kv_t kvp = fdb_kv_get_obj(db, to_save.key.c_str(), &kv);
146 if (kvp ==
nullptr) {
147 ESP_LOGV(TAG,
"fdb_kv_get_obj('%s'): nullptr - the key might not be set yet", to_save.key.c_str());
150 stored_data.data.reserve(kv.value_len);
151 fdb_blob_make(&blob, stored_data.data.data(), kv.value_len);
152 size_t actual_len = fdb_kv_get_blob(db, to_save.key.c_str(), &blob);
153 if (actual_len != kv.value_len) {
154 ESP_LOGV(TAG,
"fdb_kv_get_blob('%s') len mismatch: %u != %u", to_save.key.c_str(), actual_len, kv.value_len);
157 return to_save.data != stored_data.data;
160 bool reset()
override {
161 ESP_LOGD(TAG,
"Cleaning up preferences in flash...");
162 s_pending_save.clear();
164 fdb_kv_set_default(&db);
165 fdb_kvdb_deinit(&db);
171 auto *prefs =
new LibreTinyPreferences();
182 #endif // USE_LIBRETINY
ESPPreferences * global_preferences
std::string str_sprintf(const char *fmt,...)
Implementation of SPI Controller mode.