Add a web UI to the clock firmware

- Web UI on port 80: live view of the display, choose the page (clock or
  a bitmap), bitmaps (list, show, live, edit, delete), draw / image upload
  with conversion in the browser, live mode, settings, Home Assistant
- Live view from a shadow buffer in the BROSE9323 driver (shownPixel)
- Settings in NVS with the original behaviour as defaults: schedule times,
  quarter hours, yawning Pikachu, No WiFi screen, flip time, status LED,
  Home Assistant broker (restart on change)
- Bitmaps on LittleFS; new 320 KB partition, ota slots now 1.31 MB
- DisplayController: pages, live mode, settings; app.cpp holds the objects
- README for the recovery app; docs for the web UI
- Tests: settings, time parsing, bitmap format and names, schedule with
  settings, pages and live mode (95 total)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-13 01:52:34 +02:00
1 parent c9e0800e36
commit 2b1ac12ed7
34 files changed
+1989 -117

No files matched your search

+21 -2
View File
@@ -22,6 +22,7 @@ static char firmware_status[64] = "";
static bool firmware_status_sent = false;
static DisplayController *displayController = nullptr;
static bool enabled = false;
// The switches are not optimistic: the new state must be reported back to Home Assistant
static void onClockCommand(bool state, HASwitch *sender)
@@ -36,9 +37,15 @@ static void onPowerCommand(bool state, HASwitch *sender)
sender->setState(state);
}
void homeAssistantBegin(DisplayController &controller)
void homeAssistantBegin(DisplayController &controller, const HomeAssistantSettings &settings)
{
displayController = &controller;
enabled = settings.enabled;
if (!enabled)
{
Serial.println("Home Assistant disabled in the settings");
return;
}
device.setName(HA_DEVICE_NAME);
device.setSoftwareVersion(HA_SOFTWARE_VERSION);
@@ -62,11 +69,23 @@ void homeAssistantBegin(DisplayController &controller)
// The sensor doesn't resend its value on reconnect by itself
mqtt.onConnected([]() { firmware_status_sent = false; });
mqtt.begin(BROKER_ADDR, MQTT_USER, MQTT_PASSWORD);
// settings must stay alive: the MQTT library keeps the pointers
if (settings.host[0])
mqtt.begin(settings.host, settings.port, settings.user[0] ? settings.user : nullptr,
settings.password[0] ? settings.password : nullptr);
else
mqtt.begin(BROKER_ADDR, settings.port, MQTT_USER, MQTT_PASSWORD); // secrets.h
}
bool homeAssistantConnected()
{
return enabled && mqtt.isConnected();
}
void homeAssistantLoop()
{
if (!enabled)
return;
mqtt.loop();
if (!firmware_status_sent && firmware_status[0] && mqtt.isConnected())
firmware_status_sent = firmwareSensor.setValue(firmware_status);