Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store preferences in disk file on host platform #6428

Merged
merged 7 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 63 additions & 12 deletions esphome/components/host/preferences.cpp
Original file line number Diff line number Diff line change
@@ -1,36 +1,87 @@
#ifdef USE_HOST

#include <filesystem>
#include <fstream>
#include "preferences.h"
#include <cstring>
#include "esphome/core/preferences.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/defines.h"
#include "esphome/core/application.h"

namespace esphome {
namespace host {
namespace fs = std::filesystem;

static const char *const TAG = "host.preferences";

class HostPreferences : public ESPPreferences {
public:
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override { return {}; }
void HostPreferences::setup_() {
if (this->setup_complete_)
return;
this->filename_.append(getenv("HOME"));
this->filename_.append("/.esphome");
this->filename_.append("/prefs");
fs::create_directories(this->filename_);
this->filename_.append("/");
this->filename_.append(App.get_name());
this->filename_.append(".prefs");
FILE *fp = fopen(this->filename_.c_str(), "rb");
if (fp != nullptr) {
while (!feof((fp))) {
uint32_t key;
uint8_t len;
if (fread(&key, sizeof(key), 1, fp) != 1)
break;
if (fread(&len, sizeof(len), 1, fp) != 1)
break;
uint8_t data[len];
if (fread(data, sizeof(uint8_t), len, fp) != len)
break;
std::vector vec(data, data + len);
this->data[key] = vec;
}
fclose(fp);
}
this->setup_complete_ = true;
}

bool HostPreferences::sync() {
this->setup_();
FILE *fp = fopen(this->filename_.c_str(), "wb");
std::map<uint32_t, std::vector<uint8_t>>::iterator it;

ESPPreferenceObject make_preference(size_t length, uint32_t type) override { return {}; }
for (it = this->data.begin(); it != this->data.end(); ++it) {
fwrite(&it->first, sizeof(uint32_t), 1, fp);
uint8_t len = it->second.size();
fwrite(&len, sizeof(len), 1, fp);
fwrite(it->second.data(), sizeof(uint8_t), it->second.size(), fp);
}
fclose(fp);
return true;
}

bool HostPreferences::reset() {
host_preferences->data.clear();
return true;
}

bool sync() override { return true; }
bool reset() override { return true; }
ESPPreferenceObject HostPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
auto backend = new HostPreferenceBackend(type);
return ESPPreferenceObject(backend);
};

void setup_preferences() {
auto *pref = new HostPreferences(); // NOLINT(cppcoreguidelines-owning-memory)
host_preferences = pref;
global_preferences = pref;
}

bool HostPreferenceBackend::save(const uint8_t *data, size_t len) {
return host_preferences->save(this->key_, data, len);
}

bool HostPreferenceBackend::load(uint8_t *data, size_t len) { return host_preferences->load(this->key_, data, len); }

HostPreferences *host_preferences;
} // namespace host

ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

} // namespace esphome

#endif // USE_HOST
53 changes: 53 additions & 0 deletions esphome/components/host/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,63 @@

#ifdef USE_HOST

#include "esphome/core/preferences.h"
#include <map>

namespace esphome {
namespace host {

class HostPreferenceBackend : public ESPPreferenceBackend {
public:
explicit HostPreferenceBackend(uint32_t key) { this->key_ = key; }

bool save(const uint8_t *data, size_t len) override;
bool load(uint8_t *data, size_t len) override;

protected:
uint32_t key_{};
};

class HostPreferences : public ESPPreferences {
public:
bool sync() override;
bool reset() override;

ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override;
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
return make_preference(length, type, false);
}

bool save(uint32_t key, const uint8_t *data, size_t len) {
if (len > 255)
return false;
this->setup_();
std::vector vec(data, data + len);
this->data[key] = vec;
return true;
}

bool load(uint32_t key, uint8_t *data, size_t len) {
if (len > 255)
return false;
this->setup_();
if (this->data.count(key) == 0)
return false;
auto vec = this->data[key];
if (vec.size() != len)
return false;
memcpy(data, vec.data(), len);
return true;
}

protected:
void setup_();
bool setup_complete_{};
std::string filename_{};
std::map<uint32_t, std::vector<uint8_t>> data{};
};
void setup_preferences();
extern HostPreferences *host_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

} // namespace host
} // namespace esphome
Expand Down