Public Access
- net/ha_api: the HTTP requests run in a FreeRTOS task on core 0; loop()
only hands over copies through queues. The web UI's test button polls.
No more 3-4 s loop() stalls once a minute; timeout raised to 5 s.
- Progress bar page element (page format 4, v3 pages are converted)
- Plex user setting (settings v6): {plex_user} in entity ids
- Plex page (examples): watchers, play/pause icon, title, progress
- Bitmaps cached in RAM: a LittleFS read took ~100 ms on every render
and web preview; long JSON lists sent in 2 KB pieces
- Backup includes the refresh settings and the Plex user
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
3.1 KiB
C++
105 lines
3.1 KiB
C++
// ESP32 firmware: decides what the flipdot display shows (clock, bitmaps, web UI, Home
|
|
// Assistant) and sends it to the Nano, which drives the panels. See README.md.
|
|
// The objects and the actions on them are in app.cpp; this file only sets the order.
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include "app.h"
|
|
#include "config.h"
|
|
#include "display/bitmap_store.h"
|
|
#include "logic/status_led.h"
|
|
#include "nano_link/nano_flash_bridge.h"
|
|
#include "net/ha_api.h"
|
|
#include "net/home_assistant.h"
|
|
#include "net/wifi_ota.h"
|
|
#include "system/boot_target.h"
|
|
#include "system/firmware_guard.h"
|
|
#include "web/web_ui.h"
|
|
|
|
// Flashing the Nano over WiFi: restart it into its bootloader, switch it off afterwards.
|
|
// The controller then powers it on again with the new firmware.
|
|
NanoFlashBridge flashBridge(
|
|
NANO_FLASH_PORT, Serial2,
|
|
[](uint32_t baud) { nano.startBootloader(baud); },
|
|
[]() { nano.off(); });
|
|
|
|
void setup()
|
|
{
|
|
Serial.begin(115200);
|
|
pinMode(LED_PIN, OUTPUT);
|
|
nano.begin(); // display off until something is shown
|
|
|
|
// Decided first, before anything that could crash
|
|
BootMode boot_mode = firmwareGuardBegin();
|
|
|
|
bitmapStoreBegin();
|
|
appLoadSettings();
|
|
|
|
if (boot_mode == BootMode::Normal)
|
|
status.show("Connecting", "to WiFi...", true);
|
|
wifiBegin(); // starts the recovery app when it fails
|
|
otaBegin();
|
|
|
|
if (boot_mode == BootMode::SafeMode)
|
|
{
|
|
// Crashed too often: the recovery app, or without it only WiFi and OTA here,
|
|
// then try the main code once more
|
|
firmwareGuardSafeModeEnded();
|
|
rebootToRecovery(RecoveryReason::Crash);
|
|
status.show("Crashed 3x", "OTA only");
|
|
otaOnlyMode(SAFE_MODE_TIME, LED_PIN);
|
|
ESP.restart();
|
|
}
|
|
if (boot_mode == BootMode::PanicWindow)
|
|
{
|
|
status.show("Crashed!", "OTA open 15s");
|
|
otaOnlyMode(OTA_PANIC_WINDOW, LED_PIN);
|
|
}
|
|
|
|
flashBridge.begin();
|
|
|
|
// Shown until the time is synced over NTP
|
|
status.show("Getting", "the time...", true);
|
|
|
|
configTzTime(TIMEZONE, NTP_SERVER);
|
|
haApiBegin(); // Home Assistant values are read in a task of their own
|
|
homeAssistantBegin(controller, appSettings().home_assistant);
|
|
webUiBegin();
|
|
|
|
firmwareGuardStartWatchdog();
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
// OTA and the firmware guard come first, so they keep working whatever happens below
|
|
otaLoop();
|
|
firmwareGuardLoop(wifiConnected());
|
|
loopStats.tick(micros());
|
|
wifiWatchdog();
|
|
|
|
homeAssistantSetFirmwareStatus(firmwareGuardStatus());
|
|
homeAssistantLoop();
|
|
webUiLoop();
|
|
appLoop();
|
|
// Home Assistant values of the shown page (read by a task, never blocks)
|
|
if (haApiLoop(wifiConnected()))
|
|
controller.pageChanged();
|
|
|
|
// While the Nano is being flashed, nothing else may talk to it
|
|
if (flashBridge.handle())
|
|
return;
|
|
status.loop(); // changed flip settings, once the display is on
|
|
|
|
LocalTime now;
|
|
bool time_valid = appLocalTime(now);
|
|
appPageLoop(time_valid, now);
|
|
controller.update(millis(), time_valid, now, wifiConnected());
|
|
// Checks the frames just sent; a wrong image on the Nano (and every resync interval):
|
|
// the whole image again with the next update
|
|
if (nanoMonitor.loop(millis(), appSettings().refresh.image * 60000UL))
|
|
controller.pageChanged();
|
|
|
|
bool led = appSettings().status_led && statusLedLevel(millis(), wifiConnected(), nano.isOn());
|
|
digitalWrite(LED_PIN, led);
|
|
}
|