Files
Flipdot-display/src/esp32/main.cpp
T

93 lines
2.7 KiB
C++
Raw Normal View History

// ESP32 firmware: decides what the flipdot display shows (clock, Home Assistant switches)
// and sends it to the Nano, which drives the panels. See README.md.
#include <Arduino.h>
#include <time.h>
#include "BROSE9323.h"
#include "config.h"
#include "display/frames.h"
2026-10-13 01:34:04 +02:00
#include "display/status_screen.h"
#include "logic/display_controller.h"
#include "logic/status_led.h"
#include "nano_link/nano_flash_bridge.h"
#include "nano_link/nano_link.h"
#include "net/home_assistant.h"
#include "net/wifi_ota.h"
#include "system/boot_target.h"
#include "system/firmware_guard.h"
NanoLink nano(Serial2, NANO_RX_PIN, NANO_TX_PIN, RELAY_PIN, NANO_RESET_PIN);
BROSE9323 display(DISPLAY_WIDTH, DISPLAY_HEIGHT, PANEL_WIDTH);
FlipdotFrames frames(display);
2026-10-13 01:34:04 +02:00
StatusScreen status(display, nano);
DisplayController controller(nano, frames);
// 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);
2026-10-13 01:34:04 +02:00
nano.begin(); // display off until something is shown
// Decided first, before anything that could crash
BootMode boot_mode = firmwareGuardBegin();
2026-10-13 01:34:04 +02:00
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);
2026-10-13 01:34:04 +02:00
status.show("Crashed 3x", "OTA only");
otaOnlyMode(SAFE_MODE_TIME, LED_PIN);
ESP.restart();
}
if (boot_mode == BootMode::PanicWindow)
2026-10-13 01:34:04 +02:00
{
status.show("Crashed!", "OTA open 15s");
otaOnlyMode(OTA_PANIC_WINDOW, LED_PIN);
2026-10-13 01:34:04 +02:00
}
flashBridge.begin();
2026-10-13 01:34:04 +02:00
// Shown until the time is synced over NTP
status.show("Getting", "the time...", true);
configTzTime(TIMEZONE, NTP_SERVER);
homeAssistantBegin(controller);
firmwareGuardStartWatchdog();
}
void loop()
{
// OTA and the firmware guard come first, so they keep working whatever happens below
otaLoop();
firmwareGuardLoop(wifiConnected());
wifiWatchdog();
homeAssistantSetFirmwareStatus(firmwareGuardStatus());
homeAssistantLoop();
2026-10-13 00:35:28 +02:00
// While the Nano is being flashed, nothing else may talk to it
if (flashBridge.handle())
return;
2026-10-13 00:35:28 +02:00
struct tm now = {};
bool time_valid = getLocalTime(&now, 0);
2026-10-13 01:34:04 +02:00
controller.update(millis(), time_valid, now.tm_hour, now.tm_min, wifiConnected());
digitalWrite(LED_PIN, statusLedLevel(millis(), wifiConnected(), nano.isOn()));
}