Add a page schedule with rotation, Home Assistant trigger rules and a Stopwatch tab

- Schedule: daily blocks from a start time, each with up to 6 rotating pages
  or bitmaps (own duration), switching with the effect or instantly. A manual
  pick (Show tab, HA Mode) lasts until the next block; Back to schedule ends it.
- Rules: an HA state (=, is not, above, below) shows a page while true, adds it
  to the rotation while true, or shows it for N seconds when it becomes true.
  Each rule is polled at its own interval, with a 60 s back-off on errors.
- PageSelector (pure logic, tested) decides the shown page; schedule stored in
  NVS; HA sensor Shown page and button Back to schedule.
- Web UI: Schedule and Stopwatch tabs, bitmaps used by pages or rules in their
  own subsection, schedule in export/import. Version 2.6.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-15 21:36:56 +02:00
1 parent 47ef65ee7d
commit 93b9bec69a
25 files changed
+1217 -50

No files matched your search

+12
View File
@@ -30,6 +30,8 @@ static HASensor ipSensor("FlipDotDisplayIP");
static HAButton recoveryButton("FlipDotDisplayRecovery");
static HASwitch stopwatchSwitch("FlipDotDisplayStopwatch");
static HAButton stopwatchReset("FlipDotDisplayStopwatchReset");
static HASensor shownSensor("FlipDotDisplayShownPage");
static HAButton backButton("FlipDotDisplayBackToSchedule");
// Removed entities: their retained discovery config is cleared, so Home Assistant
// deletes them instead of showing them as unavailable
@@ -61,6 +63,7 @@ struct TextSensor
static TextSensor firmware = {firmwareSensor, "", false};
static TextSensor ip = {ipSensor, "", false};
static TextSensor shownPage = {shownSensor, "", false};
static DisplayController *displayController = nullptr;
static bool enabled = false;
@@ -233,6 +236,12 @@ void homeAssistantBegin(DisplayController &controller, const HomeAssistantSettin
recoveryButton.setIcon("mdi:lifebuoy");
recoveryButton.onCommand([](HAButton *) { rebootToRecovery(RecoveryReason::Manual); });
shownSensor.setName("FlipDot Display Shown page");
shownSensor.setIcon("mdi:monitor-eye");
backButton.setName("FlipDot Display Back to schedule");
backButton.setIcon("mdi:calendar-clock");
backButton.onCommand([](HAButton *) { appBackToSchedule(); });
firmwareSensor.setName("FlipDot Display Firmware");
firmwareSensor.setIcon("mdi:chip");
@@ -241,6 +250,7 @@ void homeAssistantBegin(DisplayController &controller, const HomeAssistantSettin
mqtt.onConnected([]() {
firmware.sent = false;
shownPage.sent = false;
ip.sent = false;
clearRemovedEntities();
});
@@ -271,6 +281,8 @@ void homeAssistantLoop()
ip.set(WiFi.localIP().toString().c_str());
}
ip.loop();
shownPage.set(appShownPage());
shownPage.loop();
firmware.loop();
mode.update();
offImage.update();