Home Assistant requests in a task, progress bar, Plex page, bitmap cache

- net/ha_api: the HTTP requests run in a FreeRTOS task on core 0; loop()
  only hands over copies through queues. The web UI's test button polls.
  No more 3-4 s loop() stalls once a minute; timeout raised to 5 s.
- Progress bar page element (page format 4, v3 pages are converted)
- Plex user setting (settings v6): {plex_user} in entity ids
- Plex page (examples): watchers, play/pause icon, title, progress
- Bitmaps cached in RAM: a LittleFS read took ~100 ms on every render
  and web preview; long JSON lists sent in 2 KB pieces
- Backup includes the refresh settings and the Plex user

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-16 16:17:23 +02:00
1 parent 090c2bf8ae
commit 490cefc360
42 files changed
+1074 -175

No files matched your search

+43 -8
View File
@@ -1,6 +1,7 @@
#include "display/bitmap_store.h"
#include <LittleFS.h>
#include <map>
#include <strings.h>
#include "display/bitmaps.h"
@@ -22,6 +23,18 @@ static const BuiltinBitmap BUILTIN[] = {
static bool mounted = false;
static uint32_t revision = 0;
// Bitmaps read before, also the names that don't exist (images try a name per state, then
// "default"). Reading one from LittleFS takes about 100 ms, and pages are drawn again for
// every frame (scrolling, seconds) and for every preview in the web UI. Cleared when a
// bitmap is saved or deleted, and when it holds CACHE_MAX names.
struct CachedBitmap
{
bool exists;
uint8_t data[BITMAP_BYTES];
};
static std::map<String, CachedBitmap> cache;
static const size_t CACHE_MAX = 64;
static const BuiltinBitmap *builtin(const char *name)
{
for (const BuiltinBitmap &b : BUILTIN)
@@ -99,7 +112,8 @@ bool bitmapExists(const char *name)
{
if (builtin(name))
return true;
return mounted && validBitmapName(name) && LittleFS.exists(path(name));
uint8_t bitmap[BITMAP_BYTES];
return loadBitmap(name, bitmap); // through the cache
}
bool loadBitmap(const char *name, uint8_t *bitmap)
@@ -110,14 +124,33 @@ bool loadBitmap(const char *name, uint8_t *bitmap)
memcpy_P(bitmap, b->data, BITMAP_BYTES);
return true;
}
if (!mounted || !validBitmapName(name))
return false;
auto cached = cache.find(name);
if (cached != cache.end())
{
if (cached->second.exists)
memcpy(bitmap, cached->second.data, BITMAP_BYTES);
return cached->second.exists;
}
// Checked first: open() logs an error for a missing file (images try names by state)
if (!mounted || !validBitmapName(name) || !LittleFS.exists(path(name)))
return false;
File file = LittleFS.open(path(name), "r");
if (!file)
return false;
bool ok = file.read(bitmap, BITMAP_BYTES) == (size_t)BITMAP_BYTES;
file.close();
bool ok = false;
if (LittleFS.exists(path(name)))
{
File file = LittleFS.open(path(name), "r");
if (file)
{
ok = file.read(bitmap, BITMAP_BYTES) == (size_t)BITMAP_BYTES;
file.close();
}
}
if (cache.size() >= CACHE_MAX)
cache.clear();
CachedBitmap &entry = cache[name];
entry.exists = ok;
if (ok)
memcpy(entry.data, bitmap, BITMAP_BYTES);
return ok;
}
@@ -138,6 +171,7 @@ const char *saveBitmap(const char *name, const uint8_t *bitmap)
bool ok = file.write(bitmap, BITMAP_BYTES) == (size_t)BITMAP_BYTES;
file.close();
revision++;
cache.clear();
return ok ? nullptr : "Storage full";
}
@@ -150,5 +184,6 @@ const char *deleteBitmap(const char *name)
if (!LittleFS.remove(path(name)))
return "Could not delete the file";
revision++;
cache.clear();
return nullptr;
}