Files
t-embed-insecam-widget/main/settings.c
T
Juli d92a2e53cc On-device menu, persistent settings and 12 favourite slots
Hold the knob to open a six-row menu: save/remove the playing camera as
a favourite (12 NVS slots), play or forget favourites, choose the
source (random insecam or favourites), time per camera, listing,
screen and ring brightness, caption, and reboot into Wi-Fi setup.
Settings live in NVS and override the Kconfig first-boot defaults.
Camera URLs are stored with their COUNTER placeholder so favourites get
a fresh cache-buster on every visit.
2026-09-17 00:57:02 +02:00

119 lines
3.5 KiB
C

#include "settings.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
#include <stdio.h>
#include <string.h>
static const char *TAG = "settings";
static nvs_handle_t nvs;
settings_t settings;
static cam_info_t favs[FAV_SLOTS];
static bool fav_used[FAV_SLOTS];
static void slot_key(int slot, char *key) { snprintf(key, 8, "fav%d", slot); }
void settings_init(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
ESP_ERROR_CHECK(nvs_open("widget", NVS_READWRITE, &nvs));
settings = (settings_t){
.interval_s = CONFIG_WIDGET_INTERVAL_S, .lcd_brightness = CONFIG_WIDGET_LCD_BRIGHTNESS,
.led_brightness = CONFIG_WIDGET_LED_BRIGHTNESS,
#if CONFIG_WIDGET_LISTING_RATING
.listing = LISTING_RATING,
#elif CONFIG_WIDGET_LISTING_NEW
.listing = LISTING_NEW,
#else
.listing = LISTING_MIXED,
#endif
.source = SOURCE_RANDOM, .caption = 1,
};
settings_t stored;
size_t len = sizeof stored;
if (nvs_get_blob(nvs, "settings", &stored, &len) == ESP_OK && len == sizeof stored) {
settings = stored;
if (settings.interval_s < 5 || settings.interval_s > 300) settings.interval_s = CONFIG_WIDGET_INTERVAL_S;
if (settings.lcd_brightness > 100) settings.lcd_brightness = 100;
if (settings.listing > LISTING_NEW) settings.listing = LISTING_MIXED;
if (settings.source > SOURCE_FAVORITES) settings.source = SOURCE_RANDOM;
}
for (int i = 0; i < FAV_SLOTS; i++) {
char key[8];
slot_key(i, key);
len = sizeof favs[i];
fav_used[i] = nvs_get_blob(nvs, key, &favs[i], &len) == ESP_OK && len == sizeof favs[i] && favs[i].url[0];
}
ESP_LOGI(TAG, "interval %us, lcd %u%%, ring %u, listing %u, source %u, %d favourites",
settings.interval_s, settings.lcd_brightness, settings.led_brightness, settings.listing,
settings.source, fav_count());
}
void settings_save(void)
{
if (nvs_set_blob(nvs, "settings", &settings, sizeof settings) != ESP_OK || nvs_commit(nvs) != ESP_OK)
ESP_LOGW(TAG, "save failed");
}
void settings_request_portal(void)
{
nvs_set_u8(nvs, "portal", 1);
nvs_commit(nvs);
}
bool settings_take_portal_request(void)
{
uint8_t v = 0;
if (nvs_get_u8(nvs, "portal", &v) != ESP_OK || !v) return false;
nvs_erase_key(nvs, "portal");
nvs_commit(nvs);
return true;
}
const cam_info_t *fav_get(int slot)
{
return (slot >= 0 && slot < FAV_SLOTS && fav_used[slot]) ? &favs[slot] : NULL;
}
void fav_set(int slot, const cam_info_t *cam)
{
if (slot < 0 || slot >= FAV_SLOTS) return;
char key[8];
slot_key(slot, key);
favs[slot] = *cam;
fav_used[slot] = true;
if (nvs_set_blob(nvs, key, &favs[slot], sizeof favs[slot]) != ESP_OK || nvs_commit(nvs) != ESP_OK)
ESP_LOGW(TAG, "favourite %d not saved", slot);
}
void fav_clear(int slot)
{
if (slot < 0 || slot >= FAV_SLOTS) return;
char key[8];
slot_key(slot, key);
fav_used[slot] = false;
nvs_erase_key(nvs, key);
nvs_commit(nvs);
}
int fav_find(const cam_info_t *cam)
{
for (int i = 0; i < FAV_SLOTS; i++)
if (fav_used[i] && favs[i].id == cam->id && !strcmp(favs[i].url, cam->url)) return i;
return -1;
}
int fav_count(void)
{
int n = 0;
for (int i = 0; i < FAV_SLOTS; i++) n += fav_used[i];
return n;
}