2026-10-13 00:56:32 +02:00
|
|
|
#include "logic/display_controller.h"
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "logic/schedule.h"
|
|
|
|
|
|
|
|
|
|
DisplayController::DisplayController(DisplayPower &power, Frames &frames) : _power(power), _frames(frames)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:52:34 +02:00
|
|
|
void DisplayController::setSettings(const ScheduleSettings &schedule, const ClockSettings &clock)
|
|
|
|
|
{
|
|
|
|
|
_schedule = schedule;
|
|
|
|
|
_clock = clock;
|
|
|
|
|
_content_revision++; // e.g. evening time changed: redraw
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayController::setPage(Page page)
|
|
|
|
|
{
|
|
|
|
|
_page = page;
|
|
|
|
|
_content_revision++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayController::pageChanged()
|
|
|
|
|
{
|
|
|
|
|
_content_revision++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayController::showLive(uint32_t now)
|
|
|
|
|
{
|
|
|
|
|
_live = true;
|
|
|
|
|
_live_since = now;
|
|
|
|
|
_content_revision++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayController::stopLive()
|
|
|
|
|
{
|
|
|
|
|
_live = false;
|
|
|
|
|
_content_revision++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DisplayController::liveActive() const
|
|
|
|
|
{
|
|
|
|
|
return _live;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 00:56:32 +02:00
|
|
|
void DisplayController::setClockEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
_clock_enabled = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayController::setPowerEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
_power_enabled = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DisplayController::clockEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return _clock_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DisplayController::powerEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return _power_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:34:04 +02:00
|
|
|
void DisplayController::update(uint32_t now, bool time_valid, int hour, int minute, bool wifi_connected)
|
2026-10-13 00:56:32 +02:00
|
|
|
{
|
2026-10-13 01:34:04 +02:00
|
|
|
if (wifi_connected)
|
|
|
|
|
_wifi_lost = false;
|
|
|
|
|
else if (!_wifi_lost)
|
|
|
|
|
{
|
|
|
|
|
_wifi_lost = true;
|
|
|
|
|
_wifi_lost_since = now;
|
|
|
|
|
}
|
2026-10-13 01:52:34 +02:00
|
|
|
bool show_no_wifi = _clock.no_wifi_screen && _wifi_lost && now - _wifi_lost_since >= NO_WIFI_SHOW_TIME;
|
|
|
|
|
|
|
|
|
|
if (_live && now - _live_since >= LIVE_TIMEOUT)
|
|
|
|
|
stopLive();
|
2026-10-13 01:34:04 +02:00
|
|
|
|
2026-10-13 00:56:32 +02:00
|
|
|
// Switched off elsewhere (power timer, Nano flashing): the Nano lost its frame
|
|
|
|
|
if (!_power.isOn())
|
|
|
|
|
_screen = Screen::Unknown;
|
|
|
|
|
|
|
|
|
|
if (_off_timer.expired(now))
|
|
|
|
|
{
|
|
|
|
|
_power.off();
|
|
|
|
|
_screen = Screen::Unknown;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!_power_enabled)
|
|
|
|
|
{
|
|
|
|
|
if (_power.isOn())
|
|
|
|
|
{
|
2026-10-13 01:52:34 +02:00
|
|
|
_showOnce(Screen::Blank);
|
2026-10-13 00:56:32 +02:00
|
|
|
_off_timer.request(now, CLEAR_BEFORE_OFF_TIME);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:52:34 +02:00
|
|
|
// Live mode from the web UI: shown right away, whatever the time
|
|
|
|
|
if (_live)
|
|
|
|
|
{
|
|
|
|
|
_off_timer.cancel();
|
|
|
|
|
_ensureOn();
|
|
|
|
|
_showOnce(Screen::Live);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 00:56:32 +02:00
|
|
|
// Keep the boot screen until the time is known
|
|
|
|
|
if (!time_valid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!_clock_enabled)
|
|
|
|
|
{
|
|
|
|
|
// The logo is only shown while the display is on; it never switches the power on
|
|
|
|
|
if (_power.isOn())
|
|
|
|
|
{
|
2026-10-13 01:52:34 +02:00
|
|
|
_showOnce(Screen::Logo);
|
2026-10-13 00:56:32 +02:00
|
|
|
_off_timer.request(now, POWER_OFF_DELAY);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:52:34 +02:00
|
|
|
switch (scheduleFor(hour, minute, _schedule))
|
2026-10-13 00:56:32 +02:00
|
|
|
{
|
|
|
|
|
case ScheduleMode::Night:
|
|
|
|
|
if (_power.isOn())
|
|
|
|
|
{
|
2026-10-13 01:52:34 +02:00
|
|
|
_showOnce(Screen::Blank);
|
2026-10-13 00:56:32 +02:00
|
|
|
_off_timer.request(now, POWER_OFF_DELAY);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ScheduleMode::Clock:
|
|
|
|
|
_off_timer.cancel();
|
2026-10-13 01:52:34 +02:00
|
|
|
_ensureOn();
|
|
|
|
|
if (_page == Page::Clock)
|
|
|
|
|
_showClock(hour, minute, show_no_wifi);
|
|
|
|
|
else
|
|
|
|
|
_showOnce(Screen::Page);
|
2026-10-13 00:56:32 +02:00
|
|
|
break;
|
|
|
|
|
case ScheduleMode::Standby:
|
2026-10-13 01:52:34 +02:00
|
|
|
// Flipdots keep their image without power, so the last image stays visible
|
2026-10-13 00:56:32 +02:00
|
|
|
if (_power.isOn())
|
|
|
|
|
_off_timer.request(now, POWER_OFF_DELAY);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:52:34 +02:00
|
|
|
void DisplayController::_ensureOn()
|
|
|
|
|
{
|
|
|
|
|
if (_power.isOn())
|
|
|
|
|
return;
|
|
|
|
|
_power.on();
|
|
|
|
|
_screen = Screen::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:34:04 +02:00
|
|
|
void DisplayController::_showClock(int hour, int minute, bool no_wifi)
|
2026-10-13 00:56:32 +02:00
|
|
|
{
|
2026-10-13 01:34:04 +02:00
|
|
|
Screen screen = no_wifi ? Screen::NoWifi : Screen::Clock;
|
2026-10-13 01:52:34 +02:00
|
|
|
bool evening = isEvening(hour, minute, _clock);
|
|
|
|
|
if (_screen == screen && _shown_hour == hour && _shown_minute == minute && _shown_evening == evening &&
|
|
|
|
|
_shown_revision == _content_revision)
|
2026-10-13 00:56:32 +02:00
|
|
|
return;
|
2026-10-13 01:34:04 +02:00
|
|
|
if (no_wifi)
|
|
|
|
|
_frames.noWifi(hour, minute);
|
|
|
|
|
else
|
2026-10-13 01:52:34 +02:00
|
|
|
_frames.clock(hour, minute, evening);
|
2026-10-13 01:34:04 +02:00
|
|
|
_screen = screen;
|
2026-10-13 00:56:32 +02:00
|
|
|
_shown_hour = hour;
|
|
|
|
|
_shown_minute = minute;
|
2026-10-13 01:52:34 +02:00
|
|
|
_shown_evening = evening;
|
|
|
|
|
_shown_revision = _content_revision;
|
2026-10-13 00:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
2026-10-13 01:52:34 +02:00
|
|
|
// Screens without the time: only sent again when they or their content changed
|
|
|
|
|
void DisplayController::_showOnce(Screen screen)
|
2026-10-13 00:56:32 +02:00
|
|
|
{
|
2026-10-13 01:52:34 +02:00
|
|
|
if (_screen == screen && _shown_revision == _content_revision)
|
2026-10-13 00:56:32 +02:00
|
|
|
return;
|
2026-10-13 01:52:34 +02:00
|
|
|
switch (screen)
|
|
|
|
|
{
|
|
|
|
|
case Screen::Page:
|
|
|
|
|
_frames.page();
|
|
|
|
|
break;
|
|
|
|
|
case Screen::Live:
|
|
|
|
|
_frames.live();
|
|
|
|
|
break;
|
|
|
|
|
case Screen::Logo:
|
|
|
|
|
_frames.logo();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_frames.blank();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
_screen = screen;
|
|
|
|
|
_shown_revision = _content_revision;
|
2026-10-13 00:56:32 +02:00
|
|
|
}
|