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

+8
View File
@@ -16,6 +16,14 @@ const char *builtinPageName(int index)
return index >= 0 && index < builtinPageCount() ? NAMES[index] : nullptr;
}
const char *builtinPageName(const char *name)
{
for (const char *n : NAMES)
if (name && sameName(n, name))
return n;
return nullptr;
}
static void clockPage(DynamicPage &page)
{
page = DynamicPage();
+4 -2
View File
@@ -2,8 +2,8 @@
#include "logic/page.h"
// The built-in dynamic pages. They can't be changed or deleted; the web UI saves an edited
// copy under a new name.
// The original dynamic pages. display/page_store stores a copy of each at boot that can be
// edited; the original is the fallback (deleting the copy resets the page).
//
// Clock Pikachu with the time in a thought bubble, yawning from 17:00 (the clock of
// the old firmware; also the default page)
@@ -12,5 +12,7 @@
int builtinPageCount();
const char *builtinPageName(int index);
// The built-in name as it is written, nullptr when it is no built-in page
const char *builtinPageName(const char *name);
// False when there is no built-in page with this name (compared without case)
bool builtinPage(const char *name, DynamicPage &page);
+1
View File
@@ -64,6 +64,7 @@ struct TriggerRule
uint16_t seconds = 30; // AddToRotation: time in the rotation; ForSeconds: how long
uint16_t interval = 10; // read the entity this often (s)
uint8_t blocks = 0; // bit i: active during block i; 0: always (also without a schedule)
bool over_manual = true; // also over a page picked by hand (false: it waits until the pick ends)
};
struct PageSchedule
+3 -2
View File
@@ -106,7 +106,7 @@ PageChoice PageSelector::update(int minute, uint32_t now)
_rule_timer[i] = false;
bool takes_over = ((r.mode == TriggerMode::WhileTrue && _rule_active[i]) ||
(r.mode == TriggerMode::ForSeconds && _rule_timer[i])) &&
ruleInBlock(r, _block);
ruleInBlock(r, _block) && (r.over_manual || !_picked);
if (takes_over)
{
choice.page = r.page;
@@ -138,7 +138,8 @@ PageChoice PageSelector::update(int minute, uint32_t now)
for (int i = 0; i < rule_count; i++)
{
const TriggerRule &r = _schedule->rules[i];
if (r.mode == TriggerMode::AddToRotation && _rule_active[i] && ruleInBlock(r, _block))
if (r.mode == TriggerMode::AddToRotation && _rule_active[i] && ruleInBlock(r, _block) &&
(r.over_manual || !_picked))
items[count++] = {r.page, r.seconds * 1000UL, ShowReason::Rotation, i};
}
+2 -1
View File
@@ -6,7 +6,8 @@
// Decides which page or bitmap is shown, from (highest priority first):
// 1. take-over rules (TriggerMode::WhileTrue / ForSeconds), in their order; a rule can be
// limited to some schedule blocks (TriggerRule::blocks)
// limited to some schedule blocks (TriggerRule::blocks), and can leave a manual pick
// alone (TriggerRule::over_manual false: also its AddToRotation page)
// 2. a manual pick (web UI, Home Assistant "Mode"), until the next schedule block starts
// 3. the schedule: the pages of the current block rotate, plus the pages of active
// AddToRotation rules