From f5e77c7eca78888165acda6b0b68383c86f53016 Mon Sep 17 00:00:00 2001 From: MangaValk Date: Tue, 20 Oct 2026 22:10:47 +0200 Subject: [PATCH] Icon cache holds all icons, icon list kept in RAM With the 17 life_ patterns there are 66 icons, more than the 64 names the cache held. It was cleared when full, so every pass over all icons (Icons tab, page previews) read each one from LittleFS again: /api/icons took 6.5 s and blocked loop() all that time. The cache now holds 128 names and forgets the missing names first. The sorted icon list is kept until an icon is saved or deleted. /api/icons: 6.6 s -> 0.12 s. Version 2.18.2, tested on the display over OTA. Co-Authored-By: Claude Opus 5.5 --- src/esp32/config.h | 2 +- src/esp32/display/icon_store.cpp | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/esp32/config.h b/src/esp32/config.h index 2ae3e60..4f6afc3 100644 --- a/src/esp32/config.h +++ b/src/esp32/config.h @@ -118,7 +118,7 @@ const uint32_t SETUP_AP_DELAY = 20000; // open the AP when WiFi fails thi const uint32_t WIFI_CONNECT_TIMEOUT = 30000; const uint32_t WIFI_RESTART_TIME = 10UL * 60 * 1000; -#define FIRMWARE_VERSION "2.18.1" +#define FIRMWARE_VERSION "2.18.2" // Home Assistant device id (do not change: Home Assistant's entities are linked to it) const uint8_t HA_DEVICE_ID[] = {0x34, 0x86, 0x5d, 0x3a, 0x08, 0x28}; diff --git a/src/esp32/display/icon_store.cpp b/src/esp32/display/icon_store.cpp index 87044a3..63dc60a 100644 --- a/src/esp32/display/icon_store.cpp +++ b/src/esp32/display/icon_store.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -49,14 +50,28 @@ static uint32_t revision = 0; static int count = -1; // Like the bitmaps (display/bitmap_store.cpp): images try a name per state, and pages are -// drawn for every frame and preview, so icons and missing names are kept in RAM +// drawn for every frame and preview, so icons and missing names are kept in RAM. Room for +// more names than there are icons: when the cache is cleared during a pass over all icons +// (Icons tab, page previews), every one of them is read again (6.5 s with 66 icons and a +// limit of 64). About 270 bytes per name. struct CachedIcon { bool exists; Icon icon; }; static std::map cache; -static const size_t CACHE_MAX = 64; +static const size_t CACHE_MAX = 128; + +// Full: first forget the missing names, only then the icons +static void makeRoom() +{ + if (cache.size() < CACHE_MAX) + return; + for (auto it = cache.begin(); it != cache.end();) + it = it->second.exists ? std::next(it) : cache.erase(it); + if (cache.size() >= CACHE_MAX) + cache.clear(); +} static String path(const char *name) { @@ -82,14 +97,22 @@ void iconStoreBegin() } } +// The sorted names, kept until an icon is saved or deleted (listing takes about a second) +static std::vector listed; +static bool listed_valid = false; + std::vector listIcons() { + if (listed_valid) + return listed; std::vector names = storedNames(DIR, ".bin"); for (const BuiltinIcon &b : BUILTIN) // not stored (no storage) if (std::none_of(names.begin(), names.end(), [&b](const String &n) { return strcasecmp(n.c_str(), b.name) == 0; })) names.push_back(b.name); std::sort(names.begin(), names.end(), [](const String &a, const String &b) { return strcasecmp(a.c_str(), b.c_str()) < 0; }); + listed = names; + listed_valid = true; return names; } @@ -138,8 +161,7 @@ bool loadIcon(const char *name, Icon &icon) } if (!ok) ok = builtinIcon(name, loaded); - if (cache.size() >= CACHE_MAX) - cache.clear(); + makeRoom(); CachedIcon &entry = cache[name]; entry.exists = ok; if (ok) @@ -173,6 +195,7 @@ const char *saveIcon(const char *name, const Icon &icon) file.close(); revision++; cache.clear(); + listed_valid = false; if (!ok) { LittleFS.remove(path(name)); // not half an icon @@ -194,5 +217,6 @@ const char *deleteIcon(const char *name) count--; revision++; cache.clear(); + listed_valid = false; return nullptr; }