ESPHome 2026.2.1
Loading...
Searching...
No Matches
preferences.cpp
Go to the documentation of this file.
1#ifdef USE_ZEPHYR
2#ifdef CONFIG_SETTINGS
3
4#include <zephyr/kernel.h>
6#include "esphome/core/log.h"
7#include <zephyr/settings/settings.h>
8#include <cinttypes>
9#include <cstring>
10
11namespace esphome {
12namespace zephyr {
13
14static const char *const TAG = "zephyr.preferences";
15
16#define ESPHOME_SETTINGS_KEY "esphome"
17
18// Buffer size for key: "esphome/" (8) + max hex uint32 (8) + null terminator (1) = 17; use 20 for safety margin
19static constexpr size_t KEY_BUFFER_SIZE = 20;
20
21class ZephyrPreferenceBackend : public ESPPreferenceBackend {
22 public:
23 ZephyrPreferenceBackend(uint32_t type) { this->type_ = type; }
24 ZephyrPreferenceBackend(uint32_t type, std::vector<uint8_t> &&data) : data(std::move(data)) { this->type_ = type; }
25
26 bool save(const uint8_t *data, size_t len) override {
27 this->data.resize(len);
28 std::memcpy(this->data.data(), data, len);
29 ESP_LOGVV(TAG, "save key: %u, len: %d", this->type_, len);
30 return true;
31 }
32
33 bool load(uint8_t *data, size_t len) override {
34 if (len != this->data.size()) {
35 char key_buf[KEY_BUFFER_SIZE];
36 this->format_key(key_buf, sizeof(key_buf));
37 ESP_LOGE(TAG, "size of setting key %s changed, from: %u, to: %u", key_buf, this->data.size(), len);
38 return false;
39 }
40 std::memcpy(data, this->data.data(), len);
41 ESP_LOGVV(TAG, "load key: %u, len: %d", this->type_, len);
42 return true;
43 }
44
45 uint32_t get_type() const { return this->type_; }
46 void format_key(char *buf, size_t size) const { snprintf(buf, size, ESPHOME_SETTINGS_KEY "/%" PRIx32, this->type_); }
47
48 std::vector<uint8_t> data;
49
50 protected:
51 uint32_t type_ = 0;
52};
53
54class ZephyrPreferences : public ESPPreferences {
55 public:
56 void open() {
57 int err = settings_subsys_init();
58 if (err) {
59 ESP_LOGE(TAG, "Failed to initialize settings subsystem, err: %d", err);
60 return;
61 }
62
63 static struct settings_handler settings_cb = {
64 .name = ESPHOME_SETTINGS_KEY,
65 .h_set = load_setting,
66 .h_export = export_settings,
67 };
68
69 err = settings_register(&settings_cb);
70 if (err) {
71 ESP_LOGE(TAG, "setting_register failed, err, %d", err);
72 return;
73 }
74
75 err = settings_load_subtree(ESPHOME_SETTINGS_KEY);
76 if (err) {
77 ESP_LOGE(TAG, "Cannot load settings, err: %d", err);
78 return;
79 }
80 ESP_LOGD(TAG, "Loaded %u settings.", this->backends_.size());
81 }
82
83 ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
84 return make_preference(length, type);
85 }
86
87 ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
88 for (auto *backend : this->backends_) {
89 if (backend->get_type() == type) {
90 return ESPPreferenceObject(backend);
91 }
92 }
93 printf("type %u size %u\n", type, this->backends_.size());
94 auto *pref = new ZephyrPreferenceBackend(type); // NOLINT(cppcoreguidelines-owning-memory)
95 char key_buf[KEY_BUFFER_SIZE];
96 pref->format_key(key_buf, sizeof(key_buf));
97 ESP_LOGD(TAG, "Add new setting %s.", key_buf);
98 this->backends_.push_back(pref);
99 return ESPPreferenceObject(pref);
100 }
101
102 bool sync() override {
103 ESP_LOGD(TAG, "Save settings");
104 int err = settings_save();
105 if (err) {
106 ESP_LOGE(TAG, "Cannot save settings, err: %d", err);
107 return false;
108 }
109 return true;
110 }
111
112 bool reset() override {
113 ESP_LOGD(TAG, "Reset settings");
114 for (auto *backend : this->backends_) {
115 // save empty delete data
116 backend->data.clear();
117 }
118 sync();
119 return true;
120 }
121
122 protected:
123 std::vector<ZephyrPreferenceBackend *> backends_;
124
125 static int load_setting(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
126 auto type = parse_hex<uint32_t>(name);
127 if (!type.has_value()) {
128 std::string full_name(ESPHOME_SETTINGS_KEY);
129 full_name += "/";
130 full_name += name;
131 // Delete unusable keys. Otherwise it will stay in flash forever.
132 settings_delete(full_name.c_str());
133 return 1;
134 }
135 std::vector<uint8_t> data(len);
136 int err = read_cb(cb_arg, data.data(), len);
137
138 ESP_LOGD(TAG, "load setting, name: %s(%u), len %u, err %u", name, *type, len, err);
139 auto *pref = new ZephyrPreferenceBackend(*type, std::move(data)); // NOLINT(cppcoreguidelines-owning-memory)
140 static_cast<ZephyrPreferences *>(global_preferences)->backends_.push_back(pref);
141 return 0;
142 }
143
144 static int export_settings(int (*cb)(const char *name, const void *value, size_t val_len)) {
145 for (auto *backend : static_cast<ZephyrPreferences *>(global_preferences)->backends_) {
146 char name[KEY_BUFFER_SIZE];
147 backend->format_key(name, sizeof(name));
148 int err = cb(name, backend->data.data(), backend->data.size());
149 ESP_LOGD(TAG, "save in flash, name %s, len %u, err %d", name, backend->data.size(), err);
150 }
151 return 0;
152 }
153};
154
155static ZephyrPreferences s_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
156
158 global_preferences = &s_preferences;
159 s_preferences.open();
160}
161
162} // namespace zephyr
163
164ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
165
166} // namespace esphome
167
168#endif
169#endif
uint16_t type
uint16_t reset
Definition ina226.h:5
const char *const TAG
Definition spi.cpp:7
num_t cb(num_t x)
Definition sun.cpp:30
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:692
size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count)
Parse bytes from a hex-encoded string into a byte array.
Definition helpers.cpp:294
size_t size
Definition helpers.h:729
ESPPreferences * global_preferences
uint16_t sync
Definition sun_gtil2.cpp:0
uint16_t length
Definition tt21100.cpp:0