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; }