Statuswoerter NTP (gruen), RTC (gelb, blinkt bei leerer Batterie) und ESP (rot), per Weboberflaeche schaltbar
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
20fc9092e6
commit
76d6ee900c
2 files changed
+210
-34
No files matched your search
+105
-17
@@ -28,8 +28,9 @@ RTC_DS1307 rtc;
|
||||
#define RTC_SDA D2
|
||||
#define RTC_SCL D1
|
||||
bool rtcOk = false;
|
||||
bool rtcBatteryEmpty = false; // RTC hat beim Start die Zeit verloren
|
||||
volatile bool ntpJustSynced = false;
|
||||
void onTimeSet(){ ntpJustSynced = true; }
|
||||
void onTimeSet(bool fromSntp){ if(fromSntp) ntpJustSynced = true; }
|
||||
|
||||
// ================= LED =================
|
||||
#define LED_PIN D4
|
||||
@@ -48,7 +49,7 @@ String ntpServer = DEFAULT_NTP;
|
||||
String tzString = DEFAULT_TZ;
|
||||
|
||||
// ================= SETTINGS =================
|
||||
#define SETTINGS_MAGIC 0x57554852UL // erkennt gueltige EEPROM-Daten
|
||||
#define SETTINGS_MAGIC 0x57554853UL // erkennt gueltige EEPROM-Daten
|
||||
|
||||
struct Settings {
|
||||
uint32_t magic;
|
||||
@@ -61,6 +62,8 @@ struct Settings {
|
||||
uint32_t bgColor;
|
||||
bool backgroundMode;
|
||||
bool nightBackgroundDisabled;
|
||||
bool statusLeds;
|
||||
int ntpShowSec;
|
||||
char ntpServer[64];
|
||||
char tzString[64];
|
||||
} settings;
|
||||
@@ -70,6 +73,8 @@ uint32_t currentColor = 0x00FFFF;
|
||||
uint32_t bgColor = 0x000000;
|
||||
bool backgroundMode = false;
|
||||
bool nightBackgroundDisabled = false;
|
||||
bool statusLeds = true; // Statuswoerter NTP/RTC/ESP anzeigen
|
||||
int ntpShowSec = 10; // Mindestdauer der gruenen NTP-Anzeige
|
||||
bool forceInstant = false;
|
||||
bool updateNeeded = true;
|
||||
int brightness = 120;
|
||||
@@ -99,6 +104,8 @@ void saveSettings(){
|
||||
settings.bgColor = bgColor;
|
||||
settings.backgroundMode = backgroundMode;
|
||||
settings.nightBackgroundDisabled = nightBackgroundDisabled;
|
||||
settings.statusLeds = statusLeds;
|
||||
settings.ntpShowSec = ntpShowSec;
|
||||
strncpy(settings.ntpServer, ntpServer.c_str(), sizeof(settings.ntpServer) - 1);
|
||||
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
|
||||
strncpy(settings.tzString, tzString.c_str(), sizeof(settings.tzString) - 1);
|
||||
@@ -120,6 +127,8 @@ void loadSettings(){
|
||||
bgColor = settings.bgColor & 0xFFFFFF;
|
||||
backgroundMode = settings.backgroundMode;
|
||||
nightBackgroundDisabled = settings.nightBackgroundDisabled;
|
||||
statusLeds = settings.statusLeds;
|
||||
ntpShowSec = constrain(settings.ntpShowSec, 1, 60);
|
||||
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
|
||||
settings.tzString[sizeof(settings.tzString) - 1] = '\0';
|
||||
ntpServer = String(settings.ntpServer);
|
||||
@@ -135,8 +144,15 @@ void loadSettings(){
|
||||
#define NTP_GUELTIG_MS 7200000UL // NTP-Sync gilt 2 h als aktuell
|
||||
unsigned long lastRtcReadMs = 0;
|
||||
unsigned long lastNtpMs = 0; // 0 = noch kein NTP-Sync seit Start
|
||||
bool ntpShowing = false; // NTP-Wort leuchtet gerade
|
||||
unsigned long ntpShowUntil = 0;
|
||||
|
||||
void readRtcToSystem(){
|
||||
bool ntpAktuell(){
|
||||
return lastNtpMs != 0 && millis() - lastNtpMs < NTP_GUELTIG_MS;
|
||||
}
|
||||
|
||||
// Liest die RTC; liefert false, wenn sie keine gueltige Zeit hat (Batterie leer).
|
||||
bool readRtcToSystem(){
|
||||
#ifdef RTC_VORHANDEN
|
||||
lastRtcReadMs = millis();
|
||||
#if defined(RTC_MODUL_DS3231)
|
||||
@@ -149,8 +165,10 @@ void readRtcToSystem(){
|
||||
struct timeval tv = { (time_t)n.unixtime(), 0 };
|
||||
settimeofday(&tv, nullptr);
|
||||
ntpJustSynced = false; // der eigene Aufruf ist keine NTP-Zeit
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void initRtc(){
|
||||
@@ -158,26 +176,71 @@ void initRtc(){
|
||||
Wire.begin(RTC_SDA, RTC_SCL);
|
||||
if(!rtc.begin()) return;
|
||||
rtcOk = true;
|
||||
readRtcToSystem();
|
||||
// Nach dem Nachstellen per NTP ist der Batteriestatus nicht mehr erkennbar,
|
||||
// daher wird er nur beim Start bestimmt.
|
||||
rtcBatteryEmpty = !readRtcToSystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Nach jeder NTP-Synchronisation die RTC nachstellen; ohne aktuellen NTP-Sync
|
||||
// stuendlich die Systemzeit aus der RTC auffrischen.
|
||||
void updateRtc(){
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(!rtcOk) return;
|
||||
void updateTimeSources(){
|
||||
if(ntpJustSynced){
|
||||
ntpJustSynced = false;
|
||||
if(timeSynced()){
|
||||
lastNtpMs = millis() ? millis() : 1;
|
||||
rtc.adjust(DateTime((uint32_t)time(nullptr)));
|
||||
}
|
||||
}
|
||||
bool ntpAktuell = lastNtpMs != 0 && millis() - lastNtpMs < NTP_GUELTIG_MS;
|
||||
if(!ntpAktuell && millis() - lastRtcReadMs >= RTC_INTERVAL_MS) readRtcToSystem();
|
||||
ntpShowing = true;
|
||||
ntpShowUntil = millis() + (unsigned long)ntpShowSec * 1000UL;
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(rtcOk) rtc.adjust(DateTime((uint32_t)time(nullptr)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(ntpShowing && (long)(millis() - ntpShowUntil) >= 0) ntpShowing = false;
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(rtcOk && !rtcBatteryEmpty && !ntpAktuell() && millis() - lastRtcReadMs >= RTC_INTERVAL_MS)
|
||||
readRtcToSystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================= STATUS-WOERTER =================
|
||||
// NTP (gruen): waehrend/kurz nach dem NTP-Abgleich
|
||||
// RTC (gelb): RTC vorhanden, aber kein aktueller NTP-Abgleich; bei leerer Batterie
|
||||
// blinkt das Wort im 10-s-Takt
|
||||
// ESP (rot): weder gueltige RTC noch NTP
|
||||
#define STATUS_GRUEN 0x00FF00
|
||||
#define STATUS_GELB 0xFFFF00
|
||||
#define STATUS_ROT 0xFF0000
|
||||
struct StatusFarben { uint32_t ntp, rtc, esp; };
|
||||
StatusFarben statusAktuell = {0, 0, 0};
|
||||
|
||||
StatusFarben berechneStatus(){
|
||||
StatusFarben st = {0, 0, 0};
|
||||
if(!statusLeds) return st;
|
||||
bool ntpOk = ntpAktuell();
|
||||
bool rtcGut = rtcOk && !rtcBatteryEmpty;
|
||||
if(ntpShowing) st.ntp = STATUS_GRUEN;
|
||||
if(rtcOk){
|
||||
if(rtcBatteryEmpty) st.rtc = ((millis() / 10000UL) & 1) ? 0 : STATUS_GELB;
|
||||
else if(!ntpOk) st.rtc = STATUS_GELB;
|
||||
}
|
||||
if(!rtcGut && !ntpOk) st.esp = STATUS_ROT;
|
||||
return st;
|
||||
}
|
||||
|
||||
// Aenderung der Statusanzeige erkennen (loest ein Neuzeichnen aus)
|
||||
bool statusGeaendert(){
|
||||
StatusFarben st = berechneStatus();
|
||||
bool changed = st.ntp != statusAktuell.ntp || st.rtc != statusAktuell.rtc || st.esp != statusAktuell.esp;
|
||||
statusAktuell = st;
|
||||
return changed;
|
||||
}
|
||||
|
||||
void applyStatus(){
|
||||
for(int i=34;i<=36;i++) if(statusAktuell.ntp) targetBuffer[i] = statusAktuell.ntp;
|
||||
for(int i=56;i<=58;i++) if(statusAktuell.rtc) targetBuffer[i] = statusAktuell.rtc;
|
||||
for(int i=67;i<=69;i++) if(statusAktuell.esp) targetBuffer[i] = statusAktuell.esp;
|
||||
}
|
||||
|
||||
// ================= HELFER =================
|
||||
bool isNightTime(struct tm *t){
|
||||
@@ -348,10 +411,21 @@ void showTimeWords(int h, int m){
|
||||
else if(hh == 7) word_SIEBEN(); else if(hh == 8) word_ACHT(); else if(hh == 9) word_NEUN();
|
||||
else if(hh == 10) word_ZEHN_H(); else if(hh == 11) word_ELF(); else word_ZWOELF();
|
||||
|
||||
applyStatus();
|
||||
|
||||
if(forceInstant){ showInstant(); forceInstant = false; }
|
||||
else { fadeToTargetSmooth(20, 10); }
|
||||
}
|
||||
|
||||
// Solange noch keine Zeit bekannt ist, nur Hintergrund und Statuswoerter zeigen
|
||||
void showStatusOnly(){
|
||||
for(int i=0;i<NUMPIXELS;i++) currentBuffer[i] = targetBuffer[i];
|
||||
uint32_t activeBg = backgroundMode ? bgColor : 0;
|
||||
for(int i=0;i<NUMPIXELS;i++) targetBuffer[i] = activeBg;
|
||||
applyStatus();
|
||||
showInstant();
|
||||
}
|
||||
|
||||
// ================= WEB HANDLERS =================
|
||||
String jsonEscape(const String &s){
|
||||
String out;
|
||||
@@ -396,7 +470,9 @@ void handleStatus(){
|
||||
json += "\"nightStart\":" + String(nightStart) + ",";
|
||||
json += "\"nightEnd\":" + String(nightEnd) + ",";
|
||||
json += "\"bg\":" + String(backgroundMode ? 1 : 0) + ",";
|
||||
json += "\"nightBgOff\":" + String(nightBackgroundDisabled ? 1 : 0);
|
||||
json += "\"nightBgOff\":" + String(nightBackgroundDisabled ? 1 : 0) + ",";
|
||||
json += "\"statusLeds\":" + String(statusLeds ? 1 : 0) + ",";
|
||||
json += "\"ntpShowSec\":" + String(ntpShowSec);
|
||||
json += "}";
|
||||
server.send(200, "application/json", json);
|
||||
}
|
||||
@@ -434,6 +510,10 @@ static const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
||||
<input type='range' id='nbr' min='0' max='255' oninput="f('/nightBrightness?val='+this.value)">
|
||||
<input type='checkbox' id='nightBgOff' onchange="f('/nightBgOff?val='+(this.checked?1:0))"> Hintergrund in Nacht aus
|
||||
</div>
|
||||
<div class='card'>
|
||||
<input type='checkbox' id='sl' onchange="f('/statusLeds?val='+(this.checked?1:0))"> <b>Status-Anzeige</b> (NTP grün, RTC gelb, ESP rot)<br><br>
|
||||
NTP-Anzeige mind. <input type='number' id='nsec' min='1' max='60' style='width:50px' oninput="if(this.value!=='')f('/ntpShowSec?val='+this.value)"> Sekunden
|
||||
</div>
|
||||
<div class='card'>
|
||||
<label>NTP Server:</label>
|
||||
<input type='text' id='ntpS' onchange="f('/setNTP?val='+encodeURIComponent(this.value))">
|
||||
@@ -450,7 +530,7 @@ static const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
||||
const s=(i,v,c=false)=>{const e=document.getElementById(i);if(e&&document.activeElement!==e){if(c)e.checked=(v==1);else e.value=v;}};
|
||||
s('col',d.color);s('br',d.brightness);s('night',d.night,true);s('nS',d.nightStart);s('nE',d.nightEnd);
|
||||
s('nbr',d.nightBrightness);s('bg',d.bg,true);s('bgcol',d.bgColor);s('ntpS',d.ntpServer);s('tzS',d.tzString);
|
||||
s('nightBgOff',d.nightBgOff,true);
|
||||
s('nightBgOff',d.nightBgOff,true);s('sl',d.statusLeds,true);s('nsec',d.ntpShowSec);
|
||||
}).catch(()=>{document.getElementById('status').innerText='Verbindung unterbrochen...';})}
|
||||
setInterval(u, 2500); u();
|
||||
</script></body></html>
|
||||
@@ -480,6 +560,8 @@ void handleNightStart(){ int v; if(!argInRange(0,23,v)) return; nightStart=v; fo
|
||||
void handleNightEnd(){ int v; if(!argInRange(0,23,v)) return; nightEnd=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNightBrightness(){ int v; if(!argInRange(0,255,v)) return; nightBrightness=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNightBgOff(){ int v; if(!argInRange(0,1,v)) return; nightBackgroundDisabled=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleStatusLeds(){ int v; if(!argInRange(0,1,v)) return; statusLeds=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNtpShowSec(){ int v; if(!argInRange(1,60,v)) return; ntpShowSec=v; sendOK(); }
|
||||
void handleBG(){ int v; if(!argInRange(0,1,v)) return; backgroundMode=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
|
||||
void handleNTP(){
|
||||
@@ -523,6 +605,8 @@ void setup(){
|
||||
server.on("/nightBrightness", handleNightBrightness);
|
||||
server.on("/nightBgOff", handleNightBgOff);
|
||||
server.on("/bg", handleBG);
|
||||
server.on("/statusLeds", handleStatusLeds);
|
||||
server.on("/ntpShowSec", handleNtpShowSec);
|
||||
server.on("/setNTP", handleNTP);
|
||||
server.on("/setTZ", handleTZ);
|
||||
server.on("/save", handleSave);
|
||||
@@ -531,10 +615,14 @@ void setup(){
|
||||
|
||||
void loop(){
|
||||
server.handleClient();
|
||||
updateRtc();
|
||||
updateTimeSources();
|
||||
if(statusGeaendert()){ forceInstant = true; updateNeeded = true; }
|
||||
|
||||
// Erst anzeigen, wenn die Zeit per NTP synchronisiert ist
|
||||
if(!timeSynced()) return;
|
||||
// Ohne bekannte Zeit nur die Statuswoerter anzeigen
|
||||
if(!timeSynced()){
|
||||
if(updateNeeded){ updateNeeded = false; forceInstant = false; showStatusOnly(); }
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
struct tm *t = localtime(&now);
|
||||
|
||||
+105
-17
@@ -28,8 +28,9 @@ RTC_DS1307 rtc;
|
||||
#define RTC_SDA D2
|
||||
#define RTC_SCL D1
|
||||
bool rtcOk = false;
|
||||
bool rtcBatteryEmpty = false; // RTC hat beim Start die Zeit verloren
|
||||
volatile bool ntpJustSynced = false;
|
||||
void onTimeSet(){ ntpJustSynced = true; }
|
||||
void onTimeSet(bool fromSntp){ if(fromSntp) ntpJustSynced = true; }
|
||||
|
||||
// ================= LED =================
|
||||
#define LED_PIN D4
|
||||
@@ -48,7 +49,7 @@ String ntpServer = DEFAULT_NTP;
|
||||
String tzString = DEFAULT_TZ;
|
||||
|
||||
// ================= SETTINGS =================
|
||||
#define SETTINGS_MAGIC 0x57554852UL // erkennt gueltige EEPROM-Daten
|
||||
#define SETTINGS_MAGIC 0x57554853UL // erkennt gueltige EEPROM-Daten
|
||||
|
||||
struct Settings {
|
||||
uint32_t magic;
|
||||
@@ -61,6 +62,8 @@ struct Settings {
|
||||
uint32_t bgColor;
|
||||
bool backgroundMode;
|
||||
bool nightBackgroundDisabled;
|
||||
bool statusLeds;
|
||||
int ntpShowSec;
|
||||
char ntpServer[64];
|
||||
char tzString[64];
|
||||
} settings;
|
||||
@@ -70,6 +73,8 @@ uint32_t currentColor = 0x00FFFF;
|
||||
uint32_t bgColor = 0x000000;
|
||||
bool backgroundMode = false;
|
||||
bool nightBackgroundDisabled = false;
|
||||
bool statusLeds = true; // Statuswoerter NTP/RTC/ESP anzeigen
|
||||
int ntpShowSec = 10; // Mindestdauer der gruenen NTP-Anzeige
|
||||
bool forceInstant = false;
|
||||
bool updateNeeded = true;
|
||||
int brightness = 120;
|
||||
@@ -99,6 +104,8 @@ void saveSettings(){
|
||||
settings.bgColor = bgColor;
|
||||
settings.backgroundMode = backgroundMode;
|
||||
settings.nightBackgroundDisabled = nightBackgroundDisabled;
|
||||
settings.statusLeds = statusLeds;
|
||||
settings.ntpShowSec = ntpShowSec;
|
||||
strncpy(settings.ntpServer, ntpServer.c_str(), sizeof(settings.ntpServer) - 1);
|
||||
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
|
||||
strncpy(settings.tzString, tzString.c_str(), sizeof(settings.tzString) - 1);
|
||||
@@ -120,6 +127,8 @@ void loadSettings(){
|
||||
bgColor = settings.bgColor & 0xFFFFFF;
|
||||
backgroundMode = settings.backgroundMode;
|
||||
nightBackgroundDisabled = settings.nightBackgroundDisabled;
|
||||
statusLeds = settings.statusLeds;
|
||||
ntpShowSec = constrain(settings.ntpShowSec, 1, 60);
|
||||
settings.ntpServer[sizeof(settings.ntpServer) - 1] = '\0';
|
||||
settings.tzString[sizeof(settings.tzString) - 1] = '\0';
|
||||
ntpServer = String(settings.ntpServer);
|
||||
@@ -135,8 +144,15 @@ void loadSettings(){
|
||||
#define NTP_GUELTIG_MS 7200000UL // NTP-Sync gilt 2 h als aktuell
|
||||
unsigned long lastRtcReadMs = 0;
|
||||
unsigned long lastNtpMs = 0; // 0 = noch kein NTP-Sync seit Start
|
||||
bool ntpShowing = false; // NTP-Wort leuchtet gerade
|
||||
unsigned long ntpShowUntil = 0;
|
||||
|
||||
void readRtcToSystem(){
|
||||
bool ntpAktuell(){
|
||||
return lastNtpMs != 0 && millis() - lastNtpMs < NTP_GUELTIG_MS;
|
||||
}
|
||||
|
||||
// Liest die RTC; liefert false, wenn sie keine gueltige Zeit hat (Batterie leer).
|
||||
bool readRtcToSystem(){
|
||||
#ifdef RTC_VORHANDEN
|
||||
lastRtcReadMs = millis();
|
||||
#if defined(RTC_MODUL_DS3231)
|
||||
@@ -149,8 +165,10 @@ void readRtcToSystem(){
|
||||
struct timeval tv = { (time_t)n.unixtime(), 0 };
|
||||
settimeofday(&tv, nullptr);
|
||||
ntpJustSynced = false; // der eigene Aufruf ist keine NTP-Zeit
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void initRtc(){
|
||||
@@ -158,26 +176,71 @@ void initRtc(){
|
||||
Wire.begin(RTC_SDA, RTC_SCL);
|
||||
if(!rtc.begin()) return;
|
||||
rtcOk = true;
|
||||
readRtcToSystem();
|
||||
// Nach dem Nachstellen per NTP ist der Batteriestatus nicht mehr erkennbar,
|
||||
// daher wird er nur beim Start bestimmt.
|
||||
rtcBatteryEmpty = !readRtcToSystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Nach jeder NTP-Synchronisation die RTC nachstellen; ohne aktuellen NTP-Sync
|
||||
// stuendlich die Systemzeit aus der RTC auffrischen.
|
||||
void updateRtc(){
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(!rtcOk) return;
|
||||
void updateTimeSources(){
|
||||
if(ntpJustSynced){
|
||||
ntpJustSynced = false;
|
||||
if(timeSynced()){
|
||||
lastNtpMs = millis() ? millis() : 1;
|
||||
rtc.adjust(DateTime((uint32_t)time(nullptr)));
|
||||
}
|
||||
}
|
||||
bool ntpAktuell = lastNtpMs != 0 && millis() - lastNtpMs < NTP_GUELTIG_MS;
|
||||
if(!ntpAktuell && millis() - lastRtcReadMs >= RTC_INTERVAL_MS) readRtcToSystem();
|
||||
ntpShowing = true;
|
||||
ntpShowUntil = millis() + (unsigned long)ntpShowSec * 1000UL;
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(rtcOk) rtc.adjust(DateTime((uint32_t)time(nullptr)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(ntpShowing && (long)(millis() - ntpShowUntil) >= 0) ntpShowing = false;
|
||||
#ifdef RTC_VORHANDEN
|
||||
if(rtcOk && !rtcBatteryEmpty && !ntpAktuell() && millis() - lastRtcReadMs >= RTC_INTERVAL_MS)
|
||||
readRtcToSystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================= STATUS-WOERTER =================
|
||||
// NTP (gruen): waehrend/kurz nach dem NTP-Abgleich
|
||||
// RTC (gelb): RTC vorhanden, aber kein aktueller NTP-Abgleich; bei leerer Batterie
|
||||
// blinkt das Wort im 10-s-Takt
|
||||
// ESP (rot): weder gueltige RTC noch NTP
|
||||
#define STATUS_GRUEN 0x00FF00
|
||||
#define STATUS_GELB 0xFFFF00
|
||||
#define STATUS_ROT 0xFF0000
|
||||
struct StatusFarben { uint32_t ntp, rtc, esp; };
|
||||
StatusFarben statusAktuell = {0, 0, 0};
|
||||
|
||||
StatusFarben berechneStatus(){
|
||||
StatusFarben st = {0, 0, 0};
|
||||
if(!statusLeds) return st;
|
||||
bool ntpOk = ntpAktuell();
|
||||
bool rtcGut = rtcOk && !rtcBatteryEmpty;
|
||||
if(ntpShowing) st.ntp = STATUS_GRUEN;
|
||||
if(rtcOk){
|
||||
if(rtcBatteryEmpty) st.rtc = ((millis() / 10000UL) & 1) ? 0 : STATUS_GELB;
|
||||
else if(!ntpOk) st.rtc = STATUS_GELB;
|
||||
}
|
||||
if(!rtcGut && !ntpOk) st.esp = STATUS_ROT;
|
||||
return st;
|
||||
}
|
||||
|
||||
// Aenderung der Statusanzeige erkennen (loest ein Neuzeichnen aus)
|
||||
bool statusGeaendert(){
|
||||
StatusFarben st = berechneStatus();
|
||||
bool changed = st.ntp != statusAktuell.ntp || st.rtc != statusAktuell.rtc || st.esp != statusAktuell.esp;
|
||||
statusAktuell = st;
|
||||
return changed;
|
||||
}
|
||||
|
||||
void applyStatus(){
|
||||
for(int i=34;i<=36;i++) if(statusAktuell.ntp) targetBuffer[i] = statusAktuell.ntp;
|
||||
for(int i=56;i<=58;i++) if(statusAktuell.rtc) targetBuffer[i] = statusAktuell.rtc;
|
||||
for(int i=67;i<=69;i++) if(statusAktuell.esp) targetBuffer[i] = statusAktuell.esp;
|
||||
}
|
||||
|
||||
// ================= HELFER =================
|
||||
bool isNightTime(struct tm *t){
|
||||
@@ -348,10 +411,21 @@ void showTimeWords(int h, int m){
|
||||
else if(hh == 7) word_SIEBEN(); else if(hh == 8) word_ACHT(); else if(hh == 9) word_NEUN();
|
||||
else if(hh == 10) word_ZEHN_H(); else if(hh == 11) word_ELF(); else word_ZWOELF();
|
||||
|
||||
applyStatus();
|
||||
|
||||
if(forceInstant){ showInstant(); forceInstant = false; }
|
||||
else { fadeToTargetSmooth(20, 10); }
|
||||
}
|
||||
|
||||
// Solange noch keine Zeit bekannt ist, nur Hintergrund und Statuswoerter zeigen
|
||||
void showStatusOnly(){
|
||||
for(int i=0;i<NUMPIXELS;i++) currentBuffer[i] = targetBuffer[i];
|
||||
uint32_t activeBg = backgroundMode ? bgColor : 0;
|
||||
for(int i=0;i<NUMPIXELS;i++) targetBuffer[i] = activeBg;
|
||||
applyStatus();
|
||||
showInstant();
|
||||
}
|
||||
|
||||
// ================= WEB HANDLERS =================
|
||||
String jsonEscape(const String &s){
|
||||
String out;
|
||||
@@ -396,7 +470,9 @@ void handleStatus(){
|
||||
json += "\"nightStart\":" + String(nightStart) + ",";
|
||||
json += "\"nightEnd\":" + String(nightEnd) + ",";
|
||||
json += "\"bg\":" + String(backgroundMode ? 1 : 0) + ",";
|
||||
json += "\"nightBgOff\":" + String(nightBackgroundDisabled ? 1 : 0);
|
||||
json += "\"nightBgOff\":" + String(nightBackgroundDisabled ? 1 : 0) + ",";
|
||||
json += "\"statusLeds\":" + String(statusLeds ? 1 : 0) + ",";
|
||||
json += "\"ntpShowSec\":" + String(ntpShowSec);
|
||||
json += "}";
|
||||
server.send(200, "application/json", json);
|
||||
}
|
||||
@@ -434,6 +510,10 @@ static const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
||||
<input type='range' id='nbr' min='0' max='255' oninput="f('/nightBrightness?val='+this.value)">
|
||||
<input type='checkbox' id='nightBgOff' onchange="f('/nightBgOff?val='+(this.checked?1:0))"> Hintergrund in Nacht aus
|
||||
</div>
|
||||
<div class='card'>
|
||||
<input type='checkbox' id='sl' onchange="f('/statusLeds?val='+(this.checked?1:0))"> <b>Status-Anzeige</b> (NTP grün, RTC gelb, ESP rot)<br><br>
|
||||
NTP-Anzeige mind. <input type='number' id='nsec' min='1' max='60' style='width:50px' oninput="if(this.value!=='')f('/ntpShowSec?val='+this.value)"> Sekunden
|
||||
</div>
|
||||
<div class='card'>
|
||||
<label>NTP Server:</label>
|
||||
<input type='text' id='ntpS' onchange="f('/setNTP?val='+encodeURIComponent(this.value))">
|
||||
@@ -450,7 +530,7 @@ static const char INDEX_HTML[] PROGMEM = R"rawliteral(
|
||||
const s=(i,v,c=false)=>{const e=document.getElementById(i);if(e&&document.activeElement!==e){if(c)e.checked=(v==1);else e.value=v;}};
|
||||
s('col',d.color);s('br',d.brightness);s('night',d.night,true);s('nS',d.nightStart);s('nE',d.nightEnd);
|
||||
s('nbr',d.nightBrightness);s('bg',d.bg,true);s('bgcol',d.bgColor);s('ntpS',d.ntpServer);s('tzS',d.tzString);
|
||||
s('nightBgOff',d.nightBgOff,true);
|
||||
s('nightBgOff',d.nightBgOff,true);s('sl',d.statusLeds,true);s('nsec',d.ntpShowSec);
|
||||
}).catch(()=>{document.getElementById('status').innerText='Verbindung unterbrochen...';})}
|
||||
setInterval(u, 2500); u();
|
||||
</script></body></html>
|
||||
@@ -480,6 +560,8 @@ void handleNightStart(){ int v; if(!argInRange(0,23,v)) return; nightStart=v; fo
|
||||
void handleNightEnd(){ int v; if(!argInRange(0,23,v)) return; nightEnd=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNightBrightness(){ int v; if(!argInRange(0,255,v)) return; nightBrightness=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNightBgOff(){ int v; if(!argInRange(0,1,v)) return; nightBackgroundDisabled=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleStatusLeds(){ int v; if(!argInRange(0,1,v)) return; statusLeds=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
void handleNtpShowSec(){ int v; if(!argInRange(1,60,v)) return; ntpShowSec=v; sendOK(); }
|
||||
void handleBG(){ int v; if(!argInRange(0,1,v)) return; backgroundMode=v; forceInstant=true; updateNeeded=true; sendOK(); }
|
||||
|
||||
void handleNTP(){
|
||||
@@ -523,6 +605,8 @@ void setup(){
|
||||
server.on("/nightBrightness", handleNightBrightness);
|
||||
server.on("/nightBgOff", handleNightBgOff);
|
||||
server.on("/bg", handleBG);
|
||||
server.on("/statusLeds", handleStatusLeds);
|
||||
server.on("/ntpShowSec", handleNtpShowSec);
|
||||
server.on("/setNTP", handleNTP);
|
||||
server.on("/setTZ", handleTZ);
|
||||
server.on("/save", handleSave);
|
||||
@@ -531,10 +615,14 @@ void setup(){
|
||||
|
||||
void loop(){
|
||||
server.handleClient();
|
||||
updateRtc();
|
||||
updateTimeSources();
|
||||
if(statusGeaendert()){ forceInstant = true; updateNeeded = true; }
|
||||
|
||||
// Erst anzeigen, wenn die Zeit per NTP synchronisiert ist
|
||||
if(!timeSynced()) return;
|
||||
// Ohne bekannte Zeit nur die Statuswoerter anzeigen
|
||||
if(!timeSynced()){
|
||||
if(updateNeeded){ updateNeeded = false; forceInstant = false; showStatusOnly(); }
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
struct tm *t = localtime(&now);
|
||||
|
||||
Reference in new issue
Block a user