From 881a20f911b1a6c6d3270d3fb910d9a9c79e997d Mon Sep 17 00:00:00 2001 From: cottongin Date: Mon, 3 Aug 2026 10:49:13 -0400 Subject: [PATCH] feat: settings manager with NVS persistence Co-authored-by: Cursor --- src/main.cpp | 11 +++++- src/settings.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ src/settings.h | 71 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/settings.cpp create mode 100644 src/settings.h diff --git a/src/main.cpp b/src/main.cpp index a2bd6f5..30c2fe8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,9 @@ #include #include #include "config.h" +#include "settings.h" + +SettingsManager settingsManager; void setup() { auto cfg = M5.config(); @@ -15,9 +18,15 @@ void setup() { pinMode(PIN_SPK_EN, OUTPUT); digitalWrite(PIN_SPK_EN, LOW); + settingsManager.begin(); + Settings settings = settingsManager.get(); + + Serial.printf("[main] Provisioned: %s\n", settingsManager.isProvisioned() ? "yes" : "no"); + Serial.printf("[main] Immich URL: %s\n", settings.immich_url.c_str()); + Serial.printf("[main] Interval: %d min\n", settings.interval_min); Serial.printf("[main] Free heap: %d, PSRAM: %d\n", ESP.getFreeHeap(), ESP.getFreePsram()); - Serial.println("[main] Boot complete (skeleton)"); + Serial.println("[main] Boot complete"); } void loop() { diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..93ad939 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,87 @@ +#include "settings.h" +#include + +static const char* NVS_NAMESPACE = "immich_frame"; +static Preferences prefs; + +void SettingsManager::begin() { + prefs.begin(NVS_NAMESPACE, false); + Serial.println("[settings] NVS initialized"); +} + +Settings SettingsManager::get() { + Settings s; + s.wifi_ssid = readString("wifi_ssid"); + s.wifi_pass = readString("wifi_pass"); + s.immich_url = readString("immich_url", DEFAULT_IMMICH_URL); + s.immich_key = readString("immich_key"); + s.interval_min = readU8("interval_m", DEFAULT_INTERVAL_MIN); + s.cycle_mode = static_cast(readU8("cycle_mode", DEFAULT_CYCLE_MODE)); + s.img_quality = static_cast(readU8("img_quality", DEFAULT_IMG_QUALITY)); + s.meta_flags = readU8("meta_flags", DEFAULT_META_FLAGS); + s.meta_pos = static_cast(readU8("meta_pos", DEFAULT_META_POS)); + s.led_brightness = readU8("led_bright", DEFAULT_LED_BRIGHTNESS); + s.queue_cursor = readU32("queue_cursor", 0); + s.albums_json = readString("albums_json", "[]"); + return s; +} + +void SettingsManager::save(const Settings& s) { + writeString("wifi_ssid", s.wifi_ssid); + writeString("wifi_pass", s.wifi_pass); + writeString("immich_url", s.immich_url); + writeString("immich_key", s.immich_key); + writeU8("interval_m", s.interval_min); + writeU8("cycle_mode", static_cast(s.cycle_mode)); + writeU8("img_quality", static_cast(s.img_quality)); + writeU8("meta_flags", s.meta_flags); + writeU8("meta_pos", static_cast(s.meta_pos)); + writeU8("led_bright", s.led_brightness); + writeU32("queue_cursor", s.queue_cursor); + writeString("albums_json", s.albums_json); + Serial.println("[settings] All settings saved"); +} + +void SettingsManager::saveField(const char* key, uint8_t value) { + writeU8(key, value); +} + +void SettingsManager::saveField(const char* key, const char* value) { + writeString(key, String(value)); +} + +void SettingsManager::factoryReset() { + prefs.clear(); + Serial.println("[settings] Factory reset — rebooting"); + delay(500); + ESP.restart(); +} + +bool SettingsManager::isProvisioned() { + String ssid = readString("wifi_ssid"); + return ssid.length() > 0; +} + +String SettingsManager::readString(const char* key, const char* defaultValue) { + return prefs.getString(key, defaultValue); +} + +uint8_t SettingsManager::readU8(const char* key, uint8_t defaultValue) { + return prefs.getUChar(key, defaultValue); +} + +uint32_t SettingsManager::readU32(const char* key, uint32_t defaultValue) { + return prefs.getUInt(key, defaultValue); +} + +void SettingsManager::writeString(const char* key, const String& value) { + prefs.putString(key, value); +} + +void SettingsManager::writeU8(const char* key, uint8_t value) { + prefs.putUChar(key, value); +} + +void SettingsManager::writeU32(const char* key, uint32_t value) { + prefs.putUInt(key, value); +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..e0b54f1 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include "config.h" + +enum class CycleMode : uint8_t { + Random = 0, + Chronological = 1, + ReverseChronological = 2, + FavoritesWeighted = 3 +}; + +enum class ImageQuality : uint8_t { + Preview = 0, + Original = 1 +}; + +enum class MetaPosition : uint8_t { + Bottom = 0, + Top = 1 +}; + +// Metadata flags bitmask +constexpr uint8_t META_DATE = 0x01; +constexpr uint8_t META_LOCATION = 0x02; +constexpr uint8_t META_PEOPLE = 0x04; +constexpr uint8_t META_ALBUM = 0x08; +constexpr uint8_t META_CAMERA = 0x10; + +struct Settings { + // WiFi + String wifi_ssid; + String wifi_pass; + + // Immich + String immich_url; + String immich_key; + + // Slideshow + uint8_t interval_min; + CycleMode cycle_mode; + ImageQuality img_quality; + + // Display + uint8_t meta_flags; + MetaPosition meta_pos; + + // Device + uint8_t led_brightness; + uint32_t queue_cursor; + String albums_json; +}; + +class SettingsManager { +public: + void begin(); + Settings get(); + void save(const Settings& s); + void saveField(const char* key, uint8_t value); + void saveField(const char* key, const char* value); + void factoryReset(); + bool isProvisioned(); + +private: + String readString(const char* key, const char* defaultValue = ""); + uint8_t readU8(const char* key, uint8_t defaultValue = 0); + uint32_t readU32(const char* key, uint32_t defaultValue = 0); + void writeString(const char* key, const String& value); + void writeU8(const char* key, uint8_t value); + void writeU32(const char* key, uint32_t value); +};