#pragma once #include #include "logic/local_time.h" #include "logic/power_timer.h" #include "logic/settings.h" // Power for the panels and the Nano (implemented by NanoLink) class DisplayPower { public: virtual bool isOn() = 0; // Switch on and wait until the Nano is ready virtual void on() = 0; virtual void off() = 0; }; // The screens the display can show (implemented by FlipdotFrames) class Frames { public: // The dynamic page selected as page, drawn for this time virtual void dynamicPage(const LocalTime &time) = 0; // Shown instead of a dynamic page while WiFi is down (the time keeps running without it) virtual void noWifi(int hour, int minute) = 0; // The bitmap selected as page virtual void page() = 0; // The image sent from the web UI's live mode virtual void live() = 0; // Left on the dots when the display switches off: blank or the off bitmap virtual void off() = 0; }; enum class Page : uint8_t { Dynamic, // a dynamic page, redrawn every minute (FlipdotFrames holds which one) Bitmap, // a bitmap (FlipdotFrames holds which one) }; // Decides what the display shows and when it is powered, based on the time, the settings, // the Home Assistant switches and the web UI. A frame is only sent when it changes. Pure // logic, tested in test/test_esp32. class DisplayController { public: DisplayController(DisplayPower &power, Frames &frames); void setSettings(const ScheduleSettings &schedule, const ClockSettings &clock); // How long the Nano takes to show a frame with the refresh effect (ms, 0 = instant). // The power stays on that much longer after the last frame. void setEffectTime(uint32_t ms); // What is shown during the day. Call pageChanged() when the page, its content (e.g. a // Home Assistant value) or the off bitmap changed. void setPage(Page page); void pageChanged(); // Live mode: show Frames::live() now, whatever the time, until stopLive() or // LIVE_TIMEOUT after the last showLive() void showLive(uint32_t now); void stopLive(); bool liveActive() const; // Home Assistant "FlipDot Display Power" switch: off clears the display and powers it off void setPowerEnabled(bool enabled); bool powerEnabled() const; // Call often (every loop). time_valid is false until the time is synced over NTP. // While WiFi is down for NO_WIFI_SHOW_TIME, "No WiFi" is shown instead of a dynamic page. void update(uint32_t now, bool time_valid, const LocalTime &time, bool wifi_connected); private: enum class Screen { Unknown, // nothing sent since the last power on Dynamic, NoWifi, Page, Live, Off, // blank or the off bitmap }; DisplayPower &_power; Frames &_frames; PowerTimer _off_timer; ScheduleSettings _schedule; ClockSettings _clock; Page _page = Page::Dynamic; uint32_t _effect_time = 0; bool _power_enabled = true; Screen _screen = Screen::Unknown; int _shown_hour = -1; int _shown_minute = -1; uint32_t _content_revision = 0; // changed page, its content, bitmap or live image uint32_t _shown_revision = 0; bool _live = false; uint32_t _live_since = 0; bool _wifi_lost = false; uint32_t _wifi_lost_since = 0; void _ensureOn(); void _showDynamic(const LocalTime &time, bool no_wifi); void _showOnce(Screen screen); };