Rules can leave a manual pick alone, Clock is an editable page, fix HA attributes

- Rules: "also over a page chosen by hand" (on by default); off, a rule
  waits until the manual pick ends. Schedule store version 3, version 2
  records are read with the option on.
- The Clock page is stored at boot from the built-in one and can be
  edited; Reset (deleting it) brings back the original.
- Home Assistant attributes were never found: ArduinoJson 7.4 takes a
  char array key as a literal of its full array length.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-16 22:13:23 +02:00
1 parent ab001e5d18
commit 51b8d87e86
37 files changed
+134 -42

No files matched your search

+27 -19
View File
@@ -301,14 +301,31 @@ static String path(const char *name)
return String(DIR) + "/" + name + EXTENSION;
}
static bool storedPage(const char *name)
{
return bitmapStorageAvailable() && validBitmapName(name) && LittleFS.exists(path(name));
}
void pageStoreBegin()
{
DynamicPage *page = new DynamicPage;
for (int i = 0; i < builtinPageCount(); i++)
if (bitmapStorageAvailable() && !storedPage(builtinPageName(i)) && builtinPage(builtinPageName(i), *page))
{
const char *error = savePage(builtinPageName(i), *page);
Serial.printf("Page \"%s\" stored from the original: %s\n", builtinPageName(i), error ? error : "ok");
}
delete page;
}
std::vector<PageInfo> listPages()
{
std::vector<PageInfo> list;
for (int i = 0; i < builtinPageCount(); i++)
list.push_back({builtinPageName(i), true});
if (!storedPage(builtinPageName(i)))
list.push_back({builtinPageName(i), true, false});
for (const String &name : storedNames(DIR, EXTENSION))
if (!builtinPageExists(name.c_str()))
list.push_back({name, false});
list.push_back({name, false, builtinPageName(name.c_str()) != nullptr});
return list;
}
@@ -319,28 +336,21 @@ uint32_t pageListRevision()
bool builtinPageExists(const char *name)
{
for (int i = 0; i < builtinPageCount(); i++)
if (sameName(builtinPageName(i), name))
return true;
return false;
return builtinPageName(name) != nullptr && !storedPage(name);
}
bool pageExists(const char *name)
{
if (builtinPageExists(name))
return true;
return bitmapStorageAvailable() && validBitmapName(name) && LittleFS.exists(path(name));
return builtinPageName(name) != nullptr || storedPage(name);
}
bool loadPage(const char *name, DynamicPage &page)
{
if (builtinPage(name, page))
return true;
if (!bitmapStorageAvailable() || !validBitmapName(name) || !LittleFS.exists(path(name)))
return false;
if (!storedPage(name))
return builtinPage(name, page);
File file = LittleFS.open(path(name), "r");
if (!file)
return false;
return builtinPage(name, page);
bool ok = false;
size_t size = file.size();
if (size == sizeof(StoredPage))
@@ -401,15 +411,13 @@ bool loadPage(const char *name, DynamicPage &page)
delete stored;
}
file.close();
return ok;
return ok || builtinPage(name, page);
}
const char *savePage(const char *name, const DynamicPage &page)
{
if (!validBitmapName(name))
return "Invalid name: use 1-24 letters, digits, spaces, - or _";
if (builtinPageExists(name))
return "A built-in page has this name";
const char *error = validatePage(page);
if (error)
return error;
@@ -435,7 +443,7 @@ const char *deletePage(const char *name)
{
if (builtinPageExists(name))
return "Built-in pages can't be deleted";
if (!bitmapStorageAvailable() || !validBitmapName(name) || !LittleFS.exists(path(name)))
if (!storedPage(name))
return "Page not found";
if (!LittleFS.remove(path(name)))
return "Could not delete the file";
+9 -2
View File
@@ -12,16 +12,23 @@
struct PageInfo
{
String name;
bool builtin;
bool builtin; // the original from logic/builtin_pages (no stored page of that name)
bool original; // a stored page that replaces a built-in one: deleting it brings that back
};
const int MAX_PAGES = 50;
// Built-in pages first, then the stored ones
// At boot: stores a copy of each built-in page that is not stored (the Clock page), so it
// can be edited like the others. The built-in one stays the fallback: deleting the stored
// copy resets it (it is stored again at the next boot).
void pageStoreBegin();
// Built-in pages without a stored copy first, then the stored ones
std::vector<PageInfo> listPages();
// Changes each time a page is saved or deleted
uint32_t pageListRevision();
bool pageExists(const char *name);
// A built-in page that no stored page replaces
bool builtinPageExists(const char *name);
bool loadPage(const char *name, DynamicPage &page);