Add SignalRGB control via WLED emulation
The clock answers like a WLED device (mDNS _wled._tcp, /json/info, /json/state, realtime UDP on 21324 and DDP on 4048), so SignalRGB can drive the 4 backlight LEDs, one per tube, LED 0 = left tube. Frames are shown at most 30 times a second (WLED_MAX_FPS); the normal effect returns 2.5 s after they stop, and the alarm flash still wins. Three new settings on the RGB page: enable (also a Home Assistant switch), stay dark while the tubes are off, and scale by the RGB brightness. They are stored in EEPROM after prm with their own magic value, so the update does not factory-reset the clock. page.js and site.css are now sent with no-cache: browsers kept them for a year and ran the old script after a web UI update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c4e0c29791
commit
ae87849e75
9 files changed
+446
-20
No files matched your search
@@ -270,6 +270,7 @@ extern char tubeDriver[]; //human-readable driver name string, shown on the web
|
||||
char webName[] = WEBNAME;
|
||||
AsyncWebServer server(80);
|
||||
#define CACHE_MAX_AGE "max-age=31536000" //maximum is: 31536000
|
||||
#define CACHE_REVALIDATE "no-cache" //page.js and site.css change with web UI updates (uploadfs): don't let browsers keep an old copy
|
||||
|
||||
#ifdef USE_WIFIMANAGER
|
||||
#include <ESPAsyncWiFiManager.h>
|
||||
@@ -342,6 +343,7 @@ bool colonBlinkState = false;
|
||||
boolean radarON = true;
|
||||
boolean mqttRadarON = true;
|
||||
volatile boolean tubesOn = true; //Tubes switch from Home Assistant (runtime only, not saved); honoured by nixie595.ino
|
||||
boolean wledLive = false; //SignalRGB/WLED frames are arriving and drive the backlight (wled.ino)
|
||||
unsigned long radarLastOn = 0;
|
||||
boolean makeFirmwareUpdate = false;
|
||||
boolean makeCathodeProtect = false;
|
||||
@@ -441,7 +443,19 @@ struct {
|
||||
int magic = MAGIC_VALUE; //magic value, to check EEPROM version when starting the clock - see loadEEPROM()/factoryReset() and the MAGIC_VALUE comment above
|
||||
} prm;
|
||||
|
||||
#define EEPROM_SIZE sizeof(prm) //EEPROM.begin() is sized exactly to the struct - no extra reserved space for future growth, so any struct change is effectively a breaking EEPROM-layout change (mitigated only by the magic-number factory-reset above)
|
||||
// Settings added by this port, stored in EEPROM right after `prm` with a magic value of their own.
|
||||
// Adding them to `prm` would change its layout, and the MAGIC_VALUE check would then factory-reset
|
||||
// the clock (WiFi settings included). If the magic value doesn't match (first boot after the update),
|
||||
// loadEEPROM() sets these defaults and leaves `prm` alone.
|
||||
#define MAGIC_VALUE_EXT 0x5701
|
||||
struct {
|
||||
boolean wledEnable = false; //SignalRGB/WLED realtime control of the backlight (wled.ino)
|
||||
boolean wledDarkWithTubes = true; //WLED frames stay dark while the tubes/backlight are off
|
||||
boolean wledUseBrightness = true; //WLED frames are scaled by the RGB brightness (and auto dim)
|
||||
uint16_t magic = MAGIC_VALUE_EXT;
|
||||
} prmExt;
|
||||
|
||||
#define EEPROM_SIZE (sizeof(prm) + sizeof(prmExt)) //no extra reserved space for future growth: a change to either struct needs its own magic value bumped
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -646,6 +660,7 @@ void Fdelay(unsigned long d) {
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
DIAG("F:ota", ArduinoOTA.handle()); //also during long animations/startup waits
|
||||
#endif
|
||||
DIAG("F:wled", wledHandle());
|
||||
DIAG("F:yield", yield());
|
||||
}
|
||||
}
|
||||
@@ -1187,8 +1202,8 @@ void startServer() {
|
||||
|
||||
DPRINTLN("Webserver: /page.js");
|
||||
if (SPIFFS.exists("/page.js")) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/page.js", "text/js");
|
||||
response->addHeader("Cache-Control", CACHE_MAX_AGE);
|
||||
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/page.js", "text/js");
|
||||
response->addHeader("Cache-Control", CACHE_REVALIDATE);
|
||||
request->send(response);
|
||||
}
|
||||
else {
|
||||
@@ -1232,8 +1247,8 @@ void startServer() {
|
||||
server.on("/site.css", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||
DPRINTLN("Webserver: /site.css");
|
||||
if (SPIFFS.exists("/site.css")) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/site.css", "text/css");
|
||||
response->addHeader("Cache-Control", CACHE_MAX_AGE);
|
||||
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/site.css", "text/css");
|
||||
response->addHeader("Cache-Control", CACHE_REVALIDATE);
|
||||
request->send(response);
|
||||
}
|
||||
else {
|
||||
@@ -1273,6 +1288,7 @@ void startServer() {
|
||||
server.on("/getConfiguration", HTTP_GET, handleSendConfig) WEB_AUTH;
|
||||
server.on("/getCurrentInfos", HTTP_GET, handleSendCurrentInfos);
|
||||
server.on("/getClockDetails", HTTP_GET, handleSendClockDetails) WEB_AUTH;
|
||||
wledRoutes(); //WLED JSON API for SignalRGB, without password (wled.ino)
|
||||
server.onNotFound(handleNotFound);
|
||||
|
||||
server.begin();
|
||||
@@ -1457,6 +1473,17 @@ void handleConfigChanged(AsyncWebServerRequest *request) {
|
||||
else if (key == "rgbMinBrightness") {
|
||||
c_MinBrightness = value.toInt();
|
||||
}
|
||||
#ifdef USE_WLED_REALTIME
|
||||
else if (key == "wledEnable") { //wledHandle() starts/stops the listeners
|
||||
prmExt.wledEnable = (value == "true");
|
||||
}
|
||||
else if (key == "wledDarkWithTubes") {
|
||||
prmExt.wledDarkWithTubes = (value == "true");
|
||||
}
|
||||
else if (key == "wledUseBrightness") {
|
||||
prmExt.wledUseBrightness = (value == "true");
|
||||
}
|
||||
#endif
|
||||
else if (key == "wifiSsid") {
|
||||
value.toCharArray(prm.wifiSsid,sizeof(prm.wifiSsid));
|
||||
}
|
||||
@@ -1683,6 +1710,11 @@ if (useTemp > 1)
|
||||
doc["rgbSpeed"] = prm.rgbSpeed; // 1..255
|
||||
doc["rgbDir"] = prm.rgbDir; // 0 = right direction, 1 = left direction
|
||||
doc["rgbMinBrightness"] = c_MinBrightness; //minimum brightness for range check!!
|
||||
#ifdef USE_WLED_REALTIME //the web page hides these switches when they are missing
|
||||
doc["wledEnable"] = prmExt.wledEnable;
|
||||
doc["wledDarkWithTubes"] = prmExt.wledDarkWithTubes;
|
||||
doc["wledUseBrightness"] = prmExt.wledUseBrightness;
|
||||
#endif
|
||||
doc["wifiMode"] = prm.wifiMode;
|
||||
doc["wifiSsid"] = prm.wifiSsid;
|
||||
doc["wifiPsw"] = prm.wifiPsw;
|
||||
@@ -1809,6 +1841,9 @@ if (useTemp > 1)
|
||||
doc["rssi"] = WiFi.RSSI();
|
||||
doc["uptime"] = millis() / 1000;
|
||||
doc["heap"] = ESP.getFreeHeap();
|
||||
#ifdef USE_WLED_REALTIME
|
||||
doc["wledLive"] = wledLive; //SignalRGB is sending frames
|
||||
#endif
|
||||
#ifdef LOOP_DIAG
|
||||
doc["stalls"] = diagReport();
|
||||
#endif
|
||||
@@ -2004,6 +2039,7 @@ void setup() {
|
||||
startMDNS();
|
||||
startServer();
|
||||
startArduinoOTA();
|
||||
wledSetup(); //after startArduinoOTA(): uses its mDNS responder
|
||||
#ifdef USE_MQTT
|
||||
setupMqtt();
|
||||
#endif
|
||||
@@ -2140,6 +2176,16 @@ void loadEEPROM() {
|
||||
|
||||
EEPROM.get(EEPROM_addr, prm);
|
||||
DPRINT(" version:"); DPRINTLN(prm.magic);
|
||||
EEPROM.get(EEPROM_addr + sizeof(prm), prmExt);
|
||||
if (prmExt.magic != MAGIC_VALUE_EXT) resetPrmExt();
|
||||
}
|
||||
|
||||
// Defaults for prmExt (not saved here: the caller saves when it needs to).
|
||||
void resetPrmExt() {
|
||||
prmExt.wledEnable = false;
|
||||
prmExt.wledDarkWithTubes = true;
|
||||
prmExt.wledUseBrightness = true;
|
||||
prmExt.magic = MAGIC_VALUE_EXT;
|
||||
}
|
||||
|
||||
// Raw single-block write of the whole `prm` struct back to EEPROM (address 0) - called after every
|
||||
@@ -2148,6 +2194,7 @@ void loadEEPROM() {
|
||||
// full-struct flash write, not just the changed bytes).
|
||||
void saveEEPROM() {
|
||||
EEPROM.put(EEPROM_addr, prm);
|
||||
EEPROM.put(EEPROM_addr + sizeof(prm), prmExt);
|
||||
EEPROM.commit();
|
||||
DPRINTLN("Settings saved to EEPROM!");
|
||||
}
|
||||
@@ -2228,6 +2275,7 @@ void factoryReset() {
|
||||
prm.corrH0 = 0;
|
||||
prm.corrH1 = 0;
|
||||
prm.magic = MAGIC_VALUE; //magic value to check the EEPROM version
|
||||
resetPrmExt();
|
||||
saveEEPROM();
|
||||
calcTime();
|
||||
}
|
||||
@@ -3345,6 +3393,7 @@ void loop(void) {
|
||||
#ifdef USE_ARDUINO_OTA
|
||||
DIAG("ota", ArduinoOTA.handle());
|
||||
#endif
|
||||
DIAG("wled", wledHandle());
|
||||
if (makeFirmwareUpdate) {
|
||||
makeFirmwareUpdate = false;
|
||||
doFirmwareUpdate();
|
||||
|
||||
Reference in new issue
Block a user