Rules can be limited to schedule blocks

Each rule has the blocks it acts in (none: always; without a running
schedule always). Stored as a block mask (schedule format 2, version 1
records are converted), in JSON as the blocks' start times. Version 2.7.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-15 22:25:00 +02:00
1 parent 87e242bf89
commit 53e9057d02
11 files changed
+166 -19

No files matched your search

+7
View File
@@ -60,6 +60,8 @@ const char *validateSchedule(const PageSchedule &s)
return "Rule times must be 1 to 3600 seconds";
if (r.interval < RULE_INTERVAL_MIN || r.interval > RULE_INTERVAL_MAX)
return "Rules are read every 2 to 600 seconds";
if (r.blocks >> s.block_count)
return "A rule is set for a block that doesn't exist";
}
return nullptr;
}
@@ -79,6 +81,11 @@ static bool number(const char *text, double &value)
return end != text && *end == '\0';
}
bool ruleInBlock(const TriggerRule &rule, int block)
{
return rule.blocks == 0 || block < 0 || (rule.blocks >> block) & 1;
}
bool ruleMatches(const TriggerRule &rule, const char *value)
{
if (value == nullptr)
+4
View File
@@ -63,6 +63,7 @@ struct TriggerRule
TriggerMode mode = TriggerMode::WhileTrue;
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)
};
struct PageSchedule
@@ -78,6 +79,9 @@ struct PageSchedule
// the pages exist.
const char *validateSchedule(const PageSchedule &schedule);
// Whether a rule acts during this block (-1: no schedule runs, then always)
bool ruleInBlock(const TriggerRule &rule, int block);
// Whether a rule's condition is true for this value (nullptr: not known, never true)
bool ruleMatches(const TriggerRule &rule, const char *value);
+4 -3
View File
@@ -104,8 +104,9 @@ PageChoice PageSelector::update(int minute, uint32_t now)
const TriggerRule &r = _schedule->rules[i];
if (r.mode == TriggerMode::ForSeconds && _rule_timer[i] && now - _rule_since[i] >= r.seconds * 1000UL)
_rule_timer[i] = false;
bool takes_over = (r.mode == TriggerMode::WhileTrue && _rule_active[i]) ||
(r.mode == TriggerMode::ForSeconds && _rule_timer[i]);
bool takes_over = ((r.mode == TriggerMode::WhileTrue && _rule_active[i]) ||
(r.mode == TriggerMode::ForSeconds && _rule_timer[i])) &&
ruleInBlock(r, _block);
if (takes_over)
{
choice.page = r.page;
@@ -137,7 +138,7 @@ 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])
if (r.mode == TriggerMode::AddToRotation && _rule_active[i] && ruleInBlock(r, _block))
items[count++] = {r.page, r.seconds * 1000UL, ShowReason::Rotation, i};
}
+2 -1
View File
@@ -5,7 +5,8 @@
#include "logic/page_schedule.h"
// Decides which page or bitmap is shown, from (highest priority first):
// 1. take-over rules (TriggerMode::WhileTrue / ForSeconds), in their order
// 1. take-over rules (TriggerMode::WhileTrue / ForSeconds), in their order; a rule can be
// limited to some schedule blocks (TriggerRule::blocks)
// 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