15static const char *
const TAG =
"esp32.preferences";
18static constexpr size_t KEY_BUFFER_SIZE = 12;
22 std::unique_ptr<uint8_t[]> data;
25 void set_data(
const uint8_t *src,
size_t size) {
26 if (!this->data || this->len != size) {
27 this->data = std::make_unique<uint8_t[]>(size);
30 memcpy(this->data.get(), src, size);
34static std::vector<NVSData> s_pending_save;
36class ESP32PreferenceBackend :
public ESPPreferenceBackend {
40 bool save(
const uint8_t *data,
size_t len)
override {
42 for (
auto &obj : s_pending_save) {
43 if (obj.key == this->key) {
44 obj.set_data(data,
len);
50 save.set_data(data,
len);
51 s_pending_save.emplace_back(std::move(save));
52 ESP_LOGVV(TAG,
"s_pending_save: key: %" PRIu32
", len: %zu", this->key,
len);
55 bool load(uint8_t *data,
size_t len)
override {
57 for (
auto &obj : s_pending_save) {
58 if (obj.key == this->key) {
63 memcpy(data, obj.data.get(),
len);
68 char key_str[KEY_BUFFER_SIZE];
69 snprintf(key_str,
sizeof(key_str),
"%" PRIu32, this->key);
71 esp_err_t err = nvs_get_blob(this->nvs_handle, key_str,
nullptr, &actual_len);
73 ESP_LOGV(TAG,
"nvs_get_blob('%s'): %s - the key might not be set yet", key_str, esp_err_to_name(err));
76 if (actual_len !=
len) {
77 ESP_LOGVV(TAG,
"NVS length does not match (%zu!=%zu)", actual_len,
len);
80 err = nvs_get_blob(this->nvs_handle, key_str, data, &
len);
82 ESP_LOGV(TAG,
"nvs_get_blob('%s') failed: %s", key_str, esp_err_to_name(err));
85 ESP_LOGVV(TAG,
"nvs_get_blob: key: %s, len: %zu", key_str,
len);
91class ESP32Preferences :
public ESPPreferences {
97 esp_err_t err = nvs_open(
"esphome", NVS_READWRITE, &nvs_handle);
101 ESP_LOGW(TAG,
"nvs_open failed: %s - erasing NVS", esp_err_to_name(err));
106 err = nvs_open(
"esphome", NVS_READWRITE, &nvs_handle);
111 ESPPreferenceObject make_preference(
size_t length, uint32_t
type,
bool in_flash)
override {
114 ESPPreferenceObject make_preference(
size_t length, uint32_t
type)
override {
115 auto *pref =
new ESP32PreferenceBackend();
116 pref->nvs_handle = this->nvs_handle;
119 return ESPPreferenceObject(pref);
122 bool sync()
override {
123 if (s_pending_save.empty())
126 ESP_LOGV(TAG,
"Saving %zu items...", s_pending_save.size());
128 int cached = 0,
written = 0, failed = 0;
129 esp_err_t last_err = ESP_OK;
133 for (
ssize_t i = s_pending_save.size() - 1; i >= 0; i--) {
134 const auto &save = s_pending_save[i];
135 char key_str[KEY_BUFFER_SIZE];
136 snprintf(key_str,
sizeof(key_str),
"%" PRIu32, save.key);
137 ESP_LOGVV(TAG,
"Checking if NVS data %s has changed", key_str);
138 if (this->is_changed_(this->nvs_handle, save, key_str)) {
139 esp_err_t err = nvs_set_blob(this->nvs_handle, key_str, save.data.get(), save.len);
140 ESP_LOGV(TAG,
"sync: key: %s, len: %zu", key_str, save.len);
142 ESP_LOGV(TAG,
"nvs_set_blob('%s', len=%zu) failed: %s", key_str, save.len, esp_err_to_name(err));
150 ESP_LOGV(TAG,
"NVS data not changed skipping %" PRIu32
" len=%zu", save.key, save.len);
153 s_pending_save.erase(s_pending_save.begin() + i);
155 ESP_LOGD(TAG,
"Writing %d items: %d cached, %d written, %d failed", cached + written + failed, cached, written,
158 ESP_LOGE(TAG,
"Writing %d items failed. Last error=%s for key=%" PRIu32, failed, esp_err_to_name(last_err),
163 esp_err_t err = nvs_commit(this->nvs_handle);
165 ESP_LOGV(TAG,
"nvs_commit() failed: %s", esp_err_to_name(err));
173 bool is_changed_(uint32_t nvs_handle,
const NVSData &to_save,
const char *key_str) {
175 esp_err_t err = nvs_get_blob(nvs_handle, key_str,
nullptr, &actual_len);
177 ESP_LOGV(TAG,
"nvs_get_blob('%s'): %s - the key might not be set yet", key_str, esp_err_to_name(err));
181 if (actual_len != to_save.len) {
184 auto stored_data = std::make_unique<uint8_t[]>(actual_len);
185 err = nvs_get_blob(nvs_handle, key_str, stored_data.get(), &actual_len);
187 ESP_LOGV(TAG,
"nvs_get_blob('%s') failed: %s", key_str, esp_err_to_name(err));
190 return memcmp(to_save.data.get(), stored_data.get(), to_save.len) != 0;
193 bool reset()
override {
194 ESP_LOGD(TAG,
"Erasing storage");
195 s_pending_save.clear();
206 auto *prefs =
new ESP32Preferences();
Providing packet encoding functions for exchanging data with a remote host.
ESPPreferences * global_preferences