Public Access
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:
1 parent
16b7856593
commit
f5e77c7eca
2 files changed
+29
-5
No files matched your search
+1
-1
@@ -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_CONNECT_TIMEOUT = 30000;
|
||||||
const uint32_t WIFI_RESTART_TIME = 10UL * 60 * 1000;
|
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)
|
// 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};
|
const uint8_t HA_DEVICE_ID[] = {0x34, 0x86, 0x5d, 0x3a, 0x08, 0x28};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
@@ -49,14 +50,28 @@ static uint32_t revision = 0;
|
|||||||
static int count = -1;
|
static int count = -1;
|
||||||
|
|
||||||
// Like the bitmaps (display/bitmap_store.cpp): images try a name per state, and pages are
|
// 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
|
struct CachedIcon
|
||||||
{
|
{
|
||||||
bool exists;
|
bool exists;
|
||||||
Icon icon;
|
Icon icon;
|
||||||
};
|
};
|
||||||
static std::map<String, CachedIcon> cache;
|
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)
|
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()
|
std::vector<String> listIcons()
|
||||||
{
|
{
|
||||||
|
if (listed_valid)
|
||||||
|
return listed;
|
||||||
std::vector<String> names = storedNames(DIR, ".bin");
|
std::vector<String> names = storedNames(DIR, ".bin");
|
||||||
for (const BuiltinIcon &b : BUILTIN) // not stored (no storage)
|
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; }))
|
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);
|
names.push_back(b.name);
|
||||||
std::sort(names.begin(), names.end(),
|
std::sort(names.begin(), names.end(),
|
||||||
[](const String &a, const String &b) { return strcasecmp(a.c_str(), b.c_str()) < 0; });
|
[](const String &a, const String &b) { return strcasecmp(a.c_str(), b.c_str()) < 0; });
|
||||||
|
listed = names;
|
||||||
|
listed_valid = true;
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,8 +161,7 @@ bool loadIcon(const char *name, Icon &icon)
|
|||||||
}
|
}
|
||||||
if (!ok)
|
if (!ok)
|
||||||
ok = builtinIcon(name, loaded);
|
ok = builtinIcon(name, loaded);
|
||||||
if (cache.size() >= CACHE_MAX)
|
makeRoom();
|
||||||
cache.clear();
|
|
||||||
CachedIcon &entry = cache[name];
|
CachedIcon &entry = cache[name];
|
||||||
entry.exists = ok;
|
entry.exists = ok;
|
||||||
if (ok)
|
if (ok)
|
||||||
@@ -173,6 +195,7 @@ const char *saveIcon(const char *name, const Icon &icon)
|
|||||||
file.close();
|
file.close();
|
||||||
revision++;
|
revision++;
|
||||||
cache.clear();
|
cache.clear();
|
||||||
|
listed_valid = false;
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
LittleFS.remove(path(name)); // not half an icon
|
LittleFS.remove(path(name)); // not half an icon
|
||||||
@@ -194,5 +217,6 @@ const char *deleteIcon(const char *name)
|
|||||||
count--;
|
count--;
|
||||||
revision++;
|
revision++;
|
||||||
cache.clear();
|
cache.clear();
|
||||||
|
listed_valid = false;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user