Public Access
Slow mode (Home Assistant switch "FlipDot Display Slow mode", dropdown
"FlipDot Display Slow mode interval", web UI Settings) makes the display
change only every 1, 2, 5, 10, 15, 20, 30 or 60 minutes, on the clock, and
powers it off in between: less noise. Nothing else is drawn meanwhile, also
no page changes. It updates at once after boot, the night, the Power switch
and live mode, and when it is switched off. Rules can override it ("show at
once in slow mode"): while their page is shown the display works normally.
Settings layout 7 and schedule layout 4 (older records are converted; they
are stored again once the firmware is marked good, so a rollback still
finds the old ones). Pages in older formats are rewritten in the current
one, in time-boxed steps. /api/status reports old_data_left.
Version 2.15.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
4.4 KiB
C
116 lines
4.4 KiB
C
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "logic/builtin_pages.h"
|
|
#include "logic/page.h"
|
|
|
|
// Everything that can be changed in the web UI. Stored in NVS (system/settings_store),
|
|
// the defaults are the original behaviour. Pure logic, tested in test/test_esp32.
|
|
//
|
|
// Times are minutes since midnight (8:00 = 480).
|
|
|
|
struct ScheduleSettings
|
|
{
|
|
bool enabled = true; // false: the display is always on
|
|
uint16_t day_start = 8 * 60; // display on from
|
|
uint16_t night_start = 23 * 60 + 31; // display off from (up to 24:00 = never)
|
|
};
|
|
|
|
// Slow mode (Home Assistant switch "FlipDot Display Slow mode", web UI): the display only
|
|
// changes every `minutes` minutes, on the clock (15: at :00 :15 :30 :45), and is powered
|
|
// off in between. Fewer flips, so less noise.
|
|
const uint8_t SLOW_MODE_MINUTES[] = {1, 2, 5, 10, 15, 20, 30, 60}; // all divide an hour
|
|
const int SLOW_MODE_MINUTES_COUNT = sizeof(SLOW_MODE_MINUTES) / sizeof(SLOW_MODE_MINUTES[0]);
|
|
struct SlowModeSettings
|
|
{
|
|
bool enabled = false;
|
|
uint8_t minutes = 15; // one of SLOW_MODE_MINUTES
|
|
};
|
|
bool validSlowModeMinutes(int minutes);
|
|
|
|
struct ClockSettings
|
|
{
|
|
bool no_wifi_screen = true; // "No WiFi" instead of a dynamic page when WiFi is down
|
|
};
|
|
|
|
struct HomeAssistantSettings
|
|
{
|
|
bool enabled = true;
|
|
char host[64] = ""; // empty: BROKER_ADDR from secrets.h
|
|
uint16_t port = 1883;
|
|
char user[32] = "";
|
|
char password[64] = "";
|
|
// Values for the dynamic pages, read over Home Assistant's REST API (net/ha_api)
|
|
char api_url[96] = ""; // empty: http://<MQTT broker>:8123
|
|
char token[256] = ""; // long-lived access token (HA user profile, Security)
|
|
};
|
|
|
|
// How the Nano drives the dots (besides the flip time). Sent to the Nano, which keeps
|
|
// them in its EEPROM. The defaults match the Nano's (src/nano/config.h).
|
|
const uint8_t DRIVE_EFFECT_INSTANT = 0; // numbers: RefreshEffect in lib/BROSE9323/dot_sequence.h
|
|
const uint8_t DRIVE_EFFECT_PUSH = 8;
|
|
const uint8_t DRIVE_EFFECT_RANDOM = 9;
|
|
const uint8_t DRIVE_EFFECT_COUNT = 10;
|
|
// Pushing flips many dots per column step, so it can take much longer than effect_time
|
|
const uint32_t DRIVE_PUSH_EXTRA_TIME = 20000;
|
|
|
|
struct DriveSettings
|
|
{
|
|
uint16_t flip_gap = 200; // pause after each pulse in us (0-5000)
|
|
uint8_t pulses = 2; // pulses for each changed dot (1-3)
|
|
uint8_t effect = DRIVE_EFFECT_INSTANT;
|
|
uint16_t effect_time = 1500; // ms (100-10000)
|
|
bool effect_small_only = false; // big changes (a new page) appear instantly
|
|
};
|
|
|
|
// Full redraws that fix the picture, in minutes (0 = never)
|
|
const uint16_t REFRESH_MINUTES_MAX = 1440;
|
|
struct RefreshSettings
|
|
{
|
|
// The Nano flips every dot once more (fixes dots that didn't flip). Sent to the Nano,
|
|
// which keeps it in its EEPROM (I command, default there: 2).
|
|
uint16_t dots = 2;
|
|
// The ESP32 sends the whole image again (fixes a wrong image on the Nano, e.g. after
|
|
// lost bytes). Only the dots that differ flip, so a correct image doesn't change.
|
|
uint16_t image = 10;
|
|
};
|
|
|
|
// What is shown during the day: the name of a dynamic page (logic/page.h) or a bitmap.
|
|
// Both share one namespace. When it is gone, the built-in Clock page is shown.
|
|
#define DEFAULT_PAGE BUILTIN_PAGE_CLOCK
|
|
// What is left on the dots when the display switches off: empty = blank, or a bitmap name
|
|
#define OFF_PAGE_BLANK ""
|
|
|
|
struct Settings
|
|
{
|
|
char page[PAGE_NAME_SIZE] = DEFAULT_PAGE;
|
|
ScheduleSettings schedule;
|
|
ClockSettings clock;
|
|
HomeAssistantSettings home_assistant;
|
|
uint16_t flip_time = 225; // flip pulse length in us, sent to the Nano
|
|
bool status_led = true;
|
|
char off_page[PAGE_NAME_SIZE] = OFF_PAGE_BLANK;
|
|
DriveSettings drive;
|
|
RefreshSettings refresh;
|
|
// Plex user name for {plex_user} in entity ids (Tautulli's sensors of that user)
|
|
char plex_user[PLEX_USER_SIZE] = "";
|
|
SlowModeSettings slow_mode;
|
|
// New fields go here, at the end (see system/settings_store.cpp)
|
|
};
|
|
|
|
// How long a new frame can take to appear on the dots in ms (0 when instant)
|
|
uint32_t effectTime(const DriveSettings &drive);
|
|
|
|
const uint16_t MINUTES_PER_DAY = 24 * 60;
|
|
const uint16_t SETTINGS_FLIP_TIME_MIN = 50;
|
|
const uint16_t SETTINGS_FLIP_TIME_MAX = 2000;
|
|
|
|
// Checks the values. Returns nullptr when they are fine, otherwise a message for the user.
|
|
const char *validateSettings(const Settings &settings);
|
|
|
|
// "HH:MM" (00:00 - 24:00) <-> minutes since midnight
|
|
bool parseTime(const char *text, uint16_t &minutes);
|
|
// out must hold 6 characters
|
|
void formatTime(uint16_t minutes, char *out);
|