mirror of
https://github.com/esphome/esphome.git
synced 2025-10-30 06:33:51 +00:00
add preferences
This commit is contained in:
@@ -17,6 +17,8 @@ from esphome.const import (
|
||||
CONF_BOARD,
|
||||
)
|
||||
|
||||
|
||||
AUTO_LOAD = ["preferences"]
|
||||
KEY_BOARD = "board"
|
||||
|
||||
|
||||
@@ -80,6 +82,9 @@ def zephyr_to_code(conf):
|
||||
zephyr_add_prj_conf("NEWLIB_LIBC_FLOAT_PRINTF", True)
|
||||
zephyr_add_prj_conf("CPLUSPLUS", True)
|
||||
zephyr_add_prj_conf("LIB_CPLUSPLUS", True)
|
||||
# preferences
|
||||
zephyr_add_prj_conf("SETTINGS", True)
|
||||
zephyr_add_prj_conf("NVS", True)
|
||||
# watchdog
|
||||
zephyr_add_prj_conf("WATCHDOG", True)
|
||||
zephyr_add_prj_conf("WDT_DISABLE_AT_BOOT", False)
|
||||
@@ -93,8 +98,10 @@ def zephyr_to_code(conf):
|
||||
zephyr_add_prj_conf("USE_SEGGER_RTT", True)
|
||||
zephyr_add_prj_conf("RTT_CONSOLE", True)
|
||||
zephyr_add_prj_conf("LOG", True)
|
||||
zephyr_add_prj_conf("LOG_BLOCK_IN_THREAD", True)
|
||||
zephyr_add_prj_conf("LOG_BUFFER_SIZE", 4096)
|
||||
zephyr_add_prj_conf("SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL", True)
|
||||
|
||||
# zephyr_add_prj_conf("USB_DEVICE_LOG_LEVEL_ERR", True)
|
||||
zephyr_add_prj_conf("USB_CDC_ACM_LOG_LEVEL_WRN", True)
|
||||
|
||||
|
||||
|
||||
@@ -2,105 +2,148 @@
|
||||
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <zephyr/settings/settings.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace zephyr {
|
||||
|
||||
static const char *const TAG = "esp32.preferences";
|
||||
static const char *const TAG = "zephyr.preferences";
|
||||
|
||||
struct NVSData {
|
||||
std::string key;
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
static std::vector<NVSData> s_pending_save; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
#define ESPHOME_SETTINGS_KEY "esphome"
|
||||
|
||||
class ZephyrPreferenceBackend : public ESPPreferenceBackend {
|
||||
public:
|
||||
std::string key;
|
||||
// uint32_t nvs_handle;
|
||||
ZephyrPreferenceBackend(uint32_t type) { this->type_ = type; }
|
||||
ZephyrPreferenceBackend(uint32_t type, std::vector<uint8_t> &&data) : data(std::move(data)) { this->type_ = type; }
|
||||
|
||||
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) {
|
||||
obj.data.assign(data, data + len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
NVSData save{};
|
||||
save.key = key;
|
||||
save.data.assign(data, data + len);
|
||||
s_pending_save.emplace_back(save);
|
||||
ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %d", key.c_str(), len);
|
||||
this->data.resize(len);
|
||||
std::memcpy(this->data.data(), data, len);
|
||||
ESP_LOGVV(TAG, "save key: %u, len: %d", type_, 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.data.size() != len) {
|
||||
// size mismatch
|
||||
return false;
|
||||
}
|
||||
memcpy(data, obj.data.data(), len);
|
||||
return true;
|
||||
}
|
||||
if (len != this->data.size()) {
|
||||
ESP_LOGE(TAG, "size of setting key %s changed, from: %u, to: %u", get_key().c_str(), this->data.size(), len);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
// size_t actual_len;
|
||||
// esp_err_t err = nvs_get_blob(nvs_handle, key.c_str(), nullptr, &actual_len);
|
||||
// if (err != 0) {
|
||||
// ESP_LOGV(TAG, "nvs_get_blob('%s'): %s - the key might not be set yet", key.c_str(), esp_err_to_name(err));
|
||||
// return false;
|
||||
// }
|
||||
// if (actual_len != len) {
|
||||
// ESP_LOGVV(TAG, "NVS length does not match (%u!=%u)", actual_len, len);
|
||||
// return false;
|
||||
// }
|
||||
// err = nvs_get_blob(nvs_handle, key.c_str(), data, &len);
|
||||
// if (err != 0) {
|
||||
// ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", key.c_str(), esp_err_to_name(err));
|
||||
// return false;
|
||||
// } else {
|
||||
// ESP_LOGVV(TAG, "nvs_get_blob: key: %s, len: %d", key.c_str(), len);
|
||||
// }
|
||||
std::memcpy(data, this->data.data(), len);
|
||||
ESP_LOGVV(TAG, "load key: %u, len: %d", type_, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint32_t get_type() const { return type_; }
|
||||
const std::string get_key() const { return str_sprintf(ESPHOME_SETTINGS_KEY "/%" PRIx32, type_); }
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
protected:
|
||||
uint32_t type_ = 0;
|
||||
};
|
||||
|
||||
class ZephyrPreferences : public ESPPreferences {
|
||||
public:
|
||||
void open() {
|
||||
int err = settings_subsys_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize settings subsystem, err: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct settings_handler settings_cb = {
|
||||
.name = ESPHOME_SETTINGS_KEY,
|
||||
.h_set = load_setting_,
|
||||
.h_export = export_settings_,
|
||||
};
|
||||
|
||||
err = settings_register(&settings_cb);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "setting_register failed, err, %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = settings_load_subtree(ESPHOME_SETTINGS_KEY);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Cannot load settings, err: %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Loaded %u settings.", backends_.size());
|
||||
}
|
||||
|
||||
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
|
||||
return make_preference(length, type);
|
||||
}
|
||||
|
||||
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
|
||||
auto *pref = new ZephyrPreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
// pref->nvs_handle = nvs_handle;
|
||||
|
||||
uint32_t keyval = type;
|
||||
pref->key = str_sprintf("%" PRIu32, keyval);
|
||||
|
||||
for (auto backend : backends_) {
|
||||
if (backend->get_type() == type) {
|
||||
return ESPPreferenceObject(backend);
|
||||
}
|
||||
}
|
||||
printf("type %u size %u\n", type, backends_.size());
|
||||
auto *pref = new ZephyrPreferenceBackend(type);
|
||||
ESP_LOGD(TAG, "Add new setting %s.", pref->get_key().c_str());
|
||||
backends_.push_back(pref);
|
||||
return ESPPreferenceObject(pref);
|
||||
}
|
||||
|
||||
bool sync() override {
|
||||
// TODO
|
||||
ESP_LOGD(TAG, "Save settings");
|
||||
int err = settings_save();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Cannot save settings, err: %d", err);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reset() override {
|
||||
// TODO
|
||||
ESP_LOGD(TAG, "Reset settings");
|
||||
for (auto backend : backends_) {
|
||||
// save empty delete data
|
||||
backend->data.clear();
|
||||
}
|
||||
sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<ZephyrPreferenceBackend *> backends_;
|
||||
|
||||
static int load_setting_(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||
auto type = parse_hex<uint32_t>(name);
|
||||
if (!type.has_value()) {
|
||||
std::string full_name(ESPHOME_SETTINGS_KEY);
|
||||
full_name += "/";
|
||||
full_name += name;
|
||||
// Delete unusable keys. Otherwise it will stay in flash forever.
|
||||
settings_delete(full_name.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::vector<uint8_t> data(len);
|
||||
int err = read_cb(cb_arg, data.data(), len);
|
||||
|
||||
ESP_LOGD(TAG, "load setting, name: %s(%u), len %u, err %u", name, *type, len, err);
|
||||
auto *pref = new ZephyrPreferenceBackend(*type, std::move(data));
|
||||
static_cast<ZephyrPreferences *>(global_preferences)->backends_.push_back(pref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int export_settings_(int (*cb)(const char *name, const void *value, size_t val_len)) {
|
||||
for (auto backend : static_cast<ZephyrPreferences *>(global_preferences)->backends_) {
|
||||
auto name = backend->get_key();
|
||||
int err = cb(name.c_str(), backend->data.data(), backend->data.size());
|
||||
ESP_LOGD(TAG, "save in flash, name %s, len %u, err %d", name.c_str(), backend->data.size(), err);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
void setup_preferences() {
|
||||
auto *prefs = new ZephyrPreferences(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
auto *prefs = new ZephyrPreferences();
|
||||
global_preferences = prefs;
|
||||
prefs->open();
|
||||
}
|
||||
|
||||
} // namespace zephyr
|
||||
|
||||
@@ -11,6 +11,7 @@ from smpclient import SMPClient
|
||||
from smpclient.mcuboot import IMAGE_TLV, ImageInfo, TLVNotFound
|
||||
from smpclient.requests.image_management import ImageStatesRead, ImageStatesWrite
|
||||
from smpclient.requests.os_management import ResetWrite
|
||||
from smp.exceptions import SMPBadStartDelimiter
|
||||
|
||||
from smpclient.generics import error, success
|
||||
from esphome.espota2 import ProgressBar
|
||||
@@ -102,9 +103,13 @@ async def smpmgr_upload(config, host, firmware):
|
||||
|
||||
_LOGGER.info(f"Connected {host}...")
|
||||
|
||||
image_state = await asyncio.wait_for(
|
||||
smp_client.request(ImageStatesRead()), timeout=SMPClient.MEDIUM_TIMEOUT
|
||||
)
|
||||
try:
|
||||
image_state = await asyncio.wait_for(
|
||||
smp_client.request(ImageStatesRead()), timeout=SMPClient.MEDIUM_TIMEOUT
|
||||
)
|
||||
except SMPBadStartDelimiter as e:
|
||||
_LOGGER.error(f"mcumgr is not supported by device ({e})")
|
||||
return 1
|
||||
|
||||
already_uploaded = False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user