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 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-20 22:10:47 +02:00
1 parent 16b7856593
commit f5e77c7eca
2 files changed
+29 -5

No files matched your search

+1 -1
View File
@@ -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};
+28 -4
View File
@@ -2,6 +2,7 @@
#include <LittleFS.h>
#include <algorithm>
#include <iterator>
#include <map>
#include <strings.h>
@@ -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<String, CachedIcon> 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<String> listed;
static bool listed_valid = false;
std::vector<String> listIcons()
{
if (listed_valid)
return listed;
std::vector<String> 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;
}