Public Access
Add a web UI to the clock firmware
- Web UI on port 80: live view of the display, choose the page (clock or a bitmap), bitmaps (list, show, live, edit, delete), draw / image upload with conversion in the browser, live mode, settings, Home Assistant - Live view from a shadow buffer in the BROSE9323 driver (shownPixel) - Settings in NVS with the original behaviour as defaults: schedule times, quarter hours, yawning Pikachu, No WiFi screen, flip time, status LED, Home Assistant broker (restart on change) - Bitmaps on LittleFS; new 320 KB partition, ota slots now 1.31 MB - DisplayController: pages, live mode, settings; app.cpp holds the objects - README for the recovery app; docs for the web UI - Tests: settings, time parsing, bitmap format and names, schedule with settings, pages and live mode (95 total) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c9e0800e36
commit
2b1ac12ed7
34 files changed
+1989
-117
No files matched your search
@@ -0,0 +1,131 @@
|
||||
#include "display/bitmap_store.h"
|
||||
|
||||
#include <LittleFS.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "display/bitmaps.h"
|
||||
|
||||
static const char *DIR = "/bitmaps";
|
||||
|
||||
struct BuiltinBitmap
|
||||
{
|
||||
const char *name;
|
||||
const uint8_t *data; // PROGMEM, BITMAP_BYTES
|
||||
};
|
||||
|
||||
static const BuiltinBitmap BUILTIN[] = {
|
||||
{"Nintendo", nintendo_bitmap_Nintendo_new},
|
||||
{"Nintendo border", nintendo_bitmap_nintendo_border},
|
||||
};
|
||||
|
||||
static bool mounted = false;
|
||||
|
||||
static const BuiltinBitmap *builtin(const char *name)
|
||||
{
|
||||
for (const BuiltinBitmap &b : BUILTIN)
|
||||
if (strcasecmp(b.name, name) == 0)
|
||||
return &b;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static String path(const char *name)
|
||||
{
|
||||
return String(DIR) + "/" + name + ".bin";
|
||||
}
|
||||
|
||||
bool bitmapStoreBegin()
|
||||
{
|
||||
mounted = LittleFS.begin(true);
|
||||
if (mounted && !LittleFS.exists(DIR))
|
||||
LittleFS.mkdir(DIR);
|
||||
Serial.printf("Bitmap storage %s\n", mounted ? "ready" : "not available (old flash layout?)");
|
||||
return mounted;
|
||||
}
|
||||
|
||||
bool bitmapStorageAvailable()
|
||||
{
|
||||
return mounted;
|
||||
}
|
||||
|
||||
void bitmapStorageUsage(size_t &used, size_t &total)
|
||||
{
|
||||
used = mounted ? LittleFS.usedBytes() : 0;
|
||||
total = mounted ? LittleFS.totalBytes() : 0;
|
||||
}
|
||||
|
||||
std::vector<BitmapInfo> listBitmaps()
|
||||
{
|
||||
std::vector<BitmapInfo> list;
|
||||
for (const BuiltinBitmap &b : BUILTIN)
|
||||
list.push_back({b.name, true});
|
||||
if (!mounted)
|
||||
return list;
|
||||
|
||||
File dir = LittleFS.open(DIR);
|
||||
for (File file = dir.openNextFile(); file; file = dir.openNextFile())
|
||||
{
|
||||
String name = file.name();
|
||||
int slash = name.lastIndexOf('/');
|
||||
if (slash >= 0)
|
||||
name = name.substring(slash + 1);
|
||||
if (!name.endsWith(".bin"))
|
||||
continue;
|
||||
name.remove(name.length() - 4);
|
||||
if (validBitmapName(name.c_str()) && !builtin(name.c_str()))
|
||||
list.push_back({name, false});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
bool bitmapExists(const char *name)
|
||||
{
|
||||
if (builtin(name))
|
||||
return true;
|
||||
return mounted && validBitmapName(name) && LittleFS.exists(path(name));
|
||||
}
|
||||
|
||||
bool loadBitmap(const char *name, uint8_t *bitmap)
|
||||
{
|
||||
const BuiltinBitmap *b = builtin(name);
|
||||
if (b)
|
||||
{
|
||||
memcpy_P(bitmap, b->data, BITMAP_BYTES);
|
||||
return true;
|
||||
}
|
||||
if (!mounted || !validBitmapName(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();
|
||||
return ok;
|
||||
}
|
||||
|
||||
const char *saveBitmap(const char *name, const uint8_t *bitmap)
|
||||
{
|
||||
if (!validBitmapName(name))
|
||||
return "Invalid name: use 1-24 letters, digits, spaces, - or _";
|
||||
if (builtin(name))
|
||||
return "A built-in bitmap has this name";
|
||||
if (!mounted)
|
||||
return "No bitmap storage (install the new flash layout over USB, see README)";
|
||||
if (!LittleFS.exists(path(name)) && listBitmaps().size() >= (size_t)MAX_BITMAPS + (sizeof(BUILTIN) / sizeof(BUILTIN[0])))
|
||||
return "Too many bitmaps, delete some first";
|
||||
|
||||
File file = LittleFS.open(path(name), "w");
|
||||
if (!file)
|
||||
return "Could not write the file";
|
||||
bool ok = file.write(bitmap, BITMAP_BYTES) == (size_t)BITMAP_BYTES;
|
||||
file.close();
|
||||
return ok ? nullptr : "Storage full";
|
||||
}
|
||||
|
||||
const char *deleteBitmap(const char *name)
|
||||
{
|
||||
if (builtin(name))
|
||||
return "Built-in bitmaps can't be deleted";
|
||||
if (!mounted || !validBitmapName(name) || !LittleFS.exists(path(name)))
|
||||
return "Bitmap not found";
|
||||
return LittleFS.remove(path(name)) ? nullptr : "Could not delete the file";
|
||||
}
|
||||
Reference in new issue
Block a user