From 583fdd082ab02e83b78fc9461e14a89f56d38ae6 Mon Sep 17 00:00:00 2001 From: Benjam Welker Date: Sun, 30 Nov 2025 13:51:14 -0700 Subject: [PATCH 01/34] add 8 more macro slots --- wled00/cfg.cpp | 15 +++++++++----- wled00/data/settings_time.htm | 39 ++++++++++++++++++----------------- wled00/ntp.cpp | 26 +++++++++++------------ wled00/set.cpp | 15 ++++++++++---- wled00/wled.h | 14 ++++++------- wled00/wled_eeprom.cpp | 7 +++++++ wled00/xml.cpp | 19 +++++++++++------ 7 files changed, 81 insertions(+), 54 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 47ba152c96..4e4a80163c 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -682,8 +682,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonArray timers = tm["ins"]; uint8_t it = 0; for (JsonObject timer : timers) { - if (it > 9) break; - if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset + if (it > 17) break; + if (it<16 && timer[F("hour")]==255) it=16; // hour==255 -> sunrise/sunset CJSON(timerHours[it], timer[F("hour")]); CJSON(timerMinutes[it], timer["min"]); CJSON(timerMacro[it], timer["macro"]); @@ -698,7 +698,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { int act = timer["en"] | actPrev; if (act) timerWeekday[it]++; } - if (it<8) { + if (it<16) { JsonObject start = timer["start"]; byte startm = start["mon"]; if (startm) timerMonth[it] = (startm << 4); @@ -711,6 +711,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } it++; } + + // Clear enabled bit for any timers that have no macro set + for (unsigned i = 0; i < 18; i++) { + if (timerMacro[i] == 0) timerWeekday[i] = timerWeekday[i] & 0b11111110; + } JsonObject ota = doc["ota"]; const char* pwd = ota["psk"]; //normally not present due to security @@ -1207,7 +1212,7 @@ void serializeConfig(JsonObject root) { JsonArray timers_ins = timers.createNestedArray("ins"); - for (unsigned i = 0; i < 10; i++) { + for (unsigned i = 0; i < 18; i++) { if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255) JsonObject timers_ins0 = timers_ins.createNestedObject(); timers_ins0["en"] = (timerWeekday[i] & 0x01); @@ -1215,7 +1220,7 @@ void serializeConfig(JsonObject root) { timers_ins0["min"] = timerMinutes[i]; timers_ins0["macro"] = timerMacro[i]; timers_ins0[F("dow")] = timerWeekday[i] >> 1; - if (i<8) { + if (i<16) { JsonObject start = timers_ins0.createNestedObject("start"); start["mon"] = (timerMonth[i] >> 4) & 0xF; start["day"] = timerDay[i]; diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 698e25b2af..fdedd5b114 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -27,7 +27,7 @@ function BTa() { var ih="En.HourMinutePreset"; - for (i=0;i<8;i++) { + for (i=0;i<16;i++) { ih+=` @@ -43,41 +43,42 @@ ih+=`
`; } - ih+=` -Sunrise - - -
📅
`; - ih+=``; - tr.innerHTML = `${ih}`; + + var timerBlock = document.createElement('div'); + timerBlock.className = 'tb'; + + var timerMain = ` +
+
+
+
+
+
+
+
+
+
+
+
📅
+
+
+ `; + + var weekdayTable = ''; + for (j=1;j<8;j++) weekdayTable += ``; + weekdayTable += '
MTWTFSS
>(j-1))&1?'checked':''}>
'; + + var dateRange = `
from to
`; + + var timerExpanded = ` + + `; + + timerBlock.innerHTML = timerMain + timerExpanded; + container.appendChild(timerBlock); } function TT(i) { var sel = gId("TS"+i); var hour = gId("H"+i); var min = gId("N"+i); var isSpecial = sel.value != 0; - hour.style.display = isSpecial ? "none" : "inline"; + hour.disabled = isSpecial; if (isSpecial) { // Save current hour value before switching to sunrise/sunset hour.setAttribute("data-regular-hour", hour.value); @@ -190,20 +212,29 @@ if (d.Sf.LNR.value==="W") { d.Sf.LN.value = -1*parseFloat(d.Sf.LN.value); } } function addRow(i,p,l,d) { - var t = gId("macros"); - var rCnt = t.rows.length; - var tr = t.insertRow(rCnt); + var container = gId("macros"); var b = String.fromCharCode((i<10?48:55)+i); var presetOpts = '' + sortedPresetOptions; - var td = document.createElement('td'); - td = tr.insertCell(0); - td.innerHTML = `Button ${i}:`; - td = tr.insertCell(1); - td.innerHTML = ``; - td = tr.insertCell(2); - td.innerHTML = ``; - td = tr.insertCell(3); - td.innerHTML = ``; + var buttonBlock = document.createElement('div'); + buttonBlock.className = 'bb'; + buttonBlock.innerHTML = ` +
Button ${i}
+
+
+ + +
+
+ + +
+
+ + +
+
+ `; + container.appendChild(buttonBlock); } function getLatLon() { if (!el) { @@ -293,24 +324,11 @@

Macro presets

Countdown-Over Preset:
Timed-Light-Over Presets:

Button actions

- - - - - - - - - - - -
push
switch
short
on->off
long
off->on
double
N/A
+
Analog Button setup

Time-controlled presets

-
-
+
-

diff --git a/wled00/data/style.css b/wled00/data/style.css index f2a9e32e09..209d39d692 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -86,9 +86,9 @@ input[type="text"], input[type="number"], input[type="password"], select { - font-size: medium; - margin: 2px; - } + font-size: medium; + margin: 2px; +} input[type="number"] { width: 4em; } @@ -144,9 +144,34 @@ td { font-size:1.5rem; cursor:pointer } -#TMT table { - width: 100%; -} +/* Timer layout - tmc=container, tb=block, tm=main, ts=section, tf=field, tfe=enabled field, te=expanded, tw=weekdays, tdr=daterange, tdf=date from/to, tc=calendar, twd=weekday text */ +.tmc{display:flex;flex-direction:column;gap:12px;max-width:800px;margin:0 auto} +.tb{background:#333;border:2px solid #444;border-radius:8px;padding:12px} +.tm{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end} +.ts{display:flex;flex-wrap:nowrap;gap:8px;align-items:flex-end} +.ts1{flex:1 0 28%;min-width:160px} +.ts2{flex:1 0 28%;min-width:160px} +.ts3{flex:1 0 38%;min-width:200px} +.tf{display:flex;flex-direction:column;gap:4px;flex:1 1 auto;min-width:70px} +.tf label{font-size:.85em;color:#aaa;align-self:center} +.tf input:not([type="checkbox"]),.tf select{box-sizing:border-box;border:2px solid #333;margin-left:auto;margin-right:auto} +.tfe{flex:0 0 auto;min-width:50px;justify-content:flex-end} +.tc{align-self:flex-end;flex:0 0 auto!important;min-width:40px} +.te{background-color:#444;margin-top:12px;padding:8px;border-radius:4px} +.twd{margin-bottom:8px} +.tw{margin:8px auto;border-collapse:collapse} +.tw th,.tw td{padding:4px 8px} +.tdr{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:8px 0} +.tdf{display:inline-flex;flex-wrap:nowrap;gap:4px;align-items:center;white-space:nowrap} + +/* Button actions - bc=container, bb=block, bh=header, bs=actions, ba=action */ +.bc{display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:16px 0} +.bb{background:#333;border:2px solid #444;border-radius:8px;padding:12px;min-width:200px;flex:1 1 auto;max-width:300px} +.bh{font-weight:bold;font-size:1.1em;margin-bottom:12px;color:#28f;text-align:center} +.bs{display:flex;flex-direction:column;gap:8px} +.ba{display:flex;flex-direction:column;gap:4px} +.ba label{font-size:.9em;color:#aaa;text-align:left} +.ba select{width:100%} #msg { display: none; @@ -205,4 +230,9 @@ td { #btns select { width: 144px; } + .button-block { + min-width: 100%; + max-width: 100%; + } + .tmc{max-width:100%} } From 0a167e8354dd75c1d32f77b5e758deb040dae1b4 Mon Sep 17 00:00:00 2001 From: benjamw Date: Tue, 16 Dec 2025 15:53:26 -0700 Subject: [PATCH 16/34] fix save bug --- wled00/data/settings_time.htm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index be3aaab0ed..1d47b4c238 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -212,8 +212,9 @@ var sel = gId("TS"+i); var hour = gId("H"+i); if (sel && sel.value != 0) { - // Re-add name attribute and set value for sunrise/sunset before submission + // Re-add name attribute, remove disabled, and set value for sunrise/sunset before submission hour.setAttribute("name", "H"+i); + hour.disabled = false; hour.value = sel.value; } } From 69ae2e1d0feda1e700bc518f26c2a4ba38371fff Mon Sep 17 00:00:00 2001 From: benjamw Date: Tue, 16 Dec 2025 17:25:23 -0700 Subject: [PATCH 17/34] make boxes a bit darker --- wled00/data/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/style.css b/wled00/data/style.css index 38d7baa7e4..e38f0cfb47 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -152,7 +152,7 @@ td { } /* Timer layout - tmc=container, tb=block, tm=main, ts=section, tf=field, tfe=enabled field, te=expanded, tw=weekdays, tdr=daterange, tdf=date from/to, tc=calendar, twd=weekday text */ .tmc{display:flex;flex-direction:column;gap:12px;max-width:800px;margin:0 auto} -.tb{background:#333;border:2px solid #444;border-radius:8px;padding:12px} +.tb{background:#282828;border:2px solid #333;border-radius:8px;padding:12px} .tm{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end} .ts{display:flex;flex-wrap:nowrap;gap:8px;align-items:flex-end} .ts1{flex:1 0 28%;min-width:160px} @@ -172,7 +172,7 @@ td { /* Button actions - bc=container, bb=block, bh=header, bs=actions, ba=action */ .bc{display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:16px 0} -.bb{background:#333;border:2px solid #444;border-radius:8px;padding:12px;min-width:200px;flex:1 1 auto;max-width:300px} +.bb{background:#282828;border:2px solid #333;border-radius:8px;padding:12px;min-width:200px;flex:1 1 auto;max-width:300px} .bh{font-weight:bold;font-size:1.1em;margin-bottom:12px;color:#28f;text-align:center} .bs{display:flex;flex-direction:column;gap:8px} .ba{display:flex;flex-direction:column;gap:4px} From c2a3269acba399c1f515a618abde5df38a3e7b6b Mon Sep 17 00:00:00 2001 From: benjamw Date: Mon, 5 Jan 2026 21:31:42 -0700 Subject: [PATCH 18/34] add fallback if localStorage is empty --- wled00/data/settings_time.htm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 1d47b4c238..ffd5d36a61 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -35,7 +35,22 @@ function loadPresets() { try { var p = localStorage.getItem("wledP"); - if (p) presets = JSON.parse(p); + if (p) { + presets = JSON.parse(p); + } else { + fetch(getURL('/presets.json'), {method: 'get'}) + .then(res => res.ok ? res.json() : {}) + .then(json => { + delete json["0"]; // remove default preset entry + presets = json; + // Save to localStorage for future use + try { localStorage.setItem("wledP", JSON.stringify(presets)); } catch(e) {} + // run here because fetch is async + buildSortedPresetOptions(); + populateMacroPresets(); + }) + .catch(e => console.log("Failed to fetch presets:", e)); + } } catch(e) {} // Load sort preference from localStorage try { From 8122f904866946cefed59d37b951d66bef518004 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 19:14:37 -0700 Subject: [PATCH 19/34] remove sort option --- wled00/data/settings_time.htm | 40 +---------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 0f4a311f2e..d4deabfcb9 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -12,7 +12,6 @@ var maxTimers = 64; var presets = {}; var sortedPresetOptions = ''; - var sortByName = false; // load common.js with retry on error (function loadFiles() { const l = document.createElement('script'); @@ -52,31 +51,11 @@ .catch(e => console.log("Failed to fetch presets:", e)); } } catch(e) {} - // Load sort preference from localStorage - try { - var sortPref = localStorage.getItem("wledPresetSort"); - if (sortPref !== null) { - sortByName = (sortPref === "name"); - // Update radio buttons to match saved preference - if (sortByName) { - var sortByNameRadio = document.getElementById("sortByName"); - if (sortByNameRadio) sortByNameRadio.checked = true; - } - } - } catch(e) {} buildSortedPresetOptions(); } function buildSortedPresetOptions() { var arr = Object.entries(presets); - if (sortByName) { - arr.sort((a,b)=>{ - var nameA = (a[1].n || ("Preset " + a[0])).toLowerCase(); - var nameB = (b[1].n || ("Preset " + b[0])).toLowerCase(); - return nameA.localeCompare(nameB); - }); - } else { - arr.sort((a,b)=> parseInt(a[0]) - parseInt(b[0])); - } + arr.sort((a,b)=> parseInt(a[0]) - parseInt(b[0])); sortedPresetOptions = ''; for (var p of arr) { if (p[0]=="0") continue; @@ -185,23 +164,6 @@ function FC() { populateMacroPresets(); } - function updateSort(byName) { - sortByName = byName; - // Save sort preference to localStorage - try { - localStorage.setItem("wledPresetSort", byName ? "name" : "id"); - } catch(e) {} - buildSortedPresetOptions(); - for (var i = 0; i < timerCount; i++) { - var sel = gId("T"+i); - if (sel) { - var val = sel.value; - sel.innerHTML = '' + sortedPresetOptions; - sel.value = val; - } - } - populateMacroPresets(); - } function populateMacroPresets() { var presetOpts = '' + sortedPresetOptions; var fields = ['A0','A1','MC','MN']; From 7fded8816053119a24167515e220fc4c355cd452 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 19:30:45 -0700 Subject: [PATCH 20/34] code rabbit suggested fixes --- wled00/data/common.js | 6 +++--- wled00/data/settings_time.htm | 13 ++++++++----- wled00/ntp.cpp | 2 +- wled00/set.cpp | 5 ++++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index c4985ce580..2b0e44c1f0 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -93,9 +93,9 @@ function loadJS(FILE_URL, async = true, preGetV = undefined, postGetV = undefine // success event scE.addEventListener("load", () => { //console.log("File loaded"); - if (preGetV) preGetV(); - if (GetV) GetV(); - if (postGetV) postGetV(); + if (typeof preGetV === "function") preGetV(); + if (typeof GetV === "function") GetV(); + if (typeof postGetV === "function") postGetV(); }); // error event scE.addEventListener("error", (ev) => { diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index d4deabfcb9..910961ac22 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -9,9 +9,12 @@ var el=false; var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; var timerCount = 0; - var maxTimers = 64; + var maxTimers; var presets = {}; var sortedPresetOptions = ''; + const TIMER_SUNRISE = 255; + const TIMER_SUNSET = 254; + const TIMER_WEEKDAYS_ALL = 255; // load common.js with retry on error (function loadFiles() { const l = document.createElement('script'); @@ -80,13 +83,13 @@ function addTimerRow(hour, minute, preset, weekdays, monthStart, dayStart, monthEnd, dayEnd) { if (timerCount >= maxTimers) return; var i = timerCount++; - var isSunrise = (hour === 255); - var isSunset = (hour === 254); + var isSunrise = (hour === TIMER_SUNRISE); + var isSunset = (hour === TIMER_SUNSET); var isSpecial = isSunrise || isSunset; if (hour === undefined) hour = 0; if (minute === undefined) minute = 0; if (preset === undefined) preset = 0; - if (weekdays === undefined) weekdays = 255; + if (weekdays === undefined) weekdays = TIMER_WEEKDAYS_ALL; if (monthStart === undefined) monthStart = 1; if (dayStart === undefined) dayStart = 1; if (monthEnd === undefined) monthEnd = 12; @@ -104,7 +107,7 @@
-
+
diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 825764eba9..74e4d119ed 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -398,7 +398,7 @@ void checkTimers() if (!sunset) continue; tt = sunset + t.minute * 60; } else { - struct tm tim; + struct tm tim = {}; tim.tm_year = year(localTime) - 1900; tim.tm_mon = month(localTime) - 1; tim.tm_mday = day(localTime); diff --git a/wled00/set.cpp b/wled00/set.cpp index 5410012636..925f273aee 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -597,7 +597,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) k[0] = 'H'; uint8_t h = request->arg(k).toInt(); k[0] = 'N'; - int8_t m = request->arg(k).toInt(); + int minuteVal = request->arg(k).toInt(); + if (minuteVal < -120) minuteVal = -120; + if (minuteVal > 120) minuteVal = 120; + int8_t m = (int8_t)minuteVal; k[0] = 'W'; uint8_t wd = request->arg(k).toInt(); uint8_t ms = 1, me = 12, ds = 1, de = 31; From 465667dd90330da5cfb580813016d0724fc71b13 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 19:31:00 -0700 Subject: [PATCH 21/34] remove css --- wled00/data/style.css | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/wled00/data/style.css b/wled00/data/style.css index d653a75e32..691b9f78cb 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -157,34 +157,6 @@ td { font-size:1.5rem; cursor:pointer } -/* Timer layout - tmc=container, tb=block, tm=main, ts=section, tf=field, tfe=enabled field, te=expanded, tw=weekdays, tdr=daterange, tdf=date from/to, tc=calendar, twd=weekday text */ -.tmc{display:flex;flex-direction:column;gap:12px;max-width:800px;margin:0 auto} -.tb{background:#282828;border:2px solid #333;border-radius:8px;padding:12px} -.tm{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-end} -.ts{display:flex;flex-wrap:nowrap;gap:8px;align-items:flex-end} -.ts1{flex:1 0 28%;min-width:160px} -.ts2{flex:1 0 28%;min-width:160px} -.ts3{flex:1 0 38%;min-width:200px} -.tf{display:flex;flex-direction:column;gap:4px;flex:1 1 auto;min-width:70px} -.tf label{font-size:.85em;color:#aaa;align-self:center} -.tf input:not([type="checkbox"]),.tf select{box-sizing:border-box;border:2px solid #333;margin-left:auto;margin-right:auto} -.tfe{flex:0 0 auto;min-width:50px;justify-content:flex-end} -.tc{align-self:flex-end;flex:0 0 auto!important;min-width:40px} -.te{background-color:#444;margin-top:12px;padding:8px;border-radius:4px} -.twd{margin-bottom:8px} -.tw{margin:8px auto;border-collapse:collapse} -.tw th,.tw td{padding:4px 8px} -.tdr{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:8px 0} -.tdf{display:inline-flex;flex-wrap:nowrap;gap:4px;align-items:center;white-space:nowrap} - -/* Button actions - bc=container, bb=block, bh=header, bs=actions, ba=action */ -.bc{display:flex;flex-wrap:wrap;gap:16px;justify-content:center;margin:16px 0} -.bb{background:#282828;border:2px solid #333;border-radius:8px;padding:12px;min-width:200px;flex:1 1 auto;max-width:300px} -.bh{font-weight:bold;font-size:1.1em;margin-bottom:12px;color:#28f;text-align:center} -.bs{display:flex;flex-direction:column;gap:8px} -.ba{display:flex;flex-direction:column;gap:4px} -.ba label{font-size:.9em;color:#aaa;text-align:left} -.ba select{width:100%} #msg { display: none; @@ -243,9 +215,4 @@ td { #btns select { width: 144px; } - .button-block { - min-width: 100%; - max-width: 100%; - } - .tmc{max-width:100%} } From 7473aa37ae5698ab6be327683d5c266a73dfbea9 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 20:53:54 -0700 Subject: [PATCH 22/34] restyling --- wled00/data/common.js | 12 ++ wled00/data/settings_time.htm | 203 ++++++++++++++++++++-------------- wled00/data/style.css | 3 + 3 files changed, 133 insertions(+), 85 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index 2b0e44c1f0..ef35730cb7 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -126,6 +126,18 @@ function getLoc() { } } function getURL(path) { return (loc ? locproto + "//" + locip : "") + path; } +async function fetchPresetsJson() { + try { + const res = await fetch(getURL('/presets.json'), {method: 'get'}); + if (!res.ok) return {}; + const json = await res.json(); + if (!json || typeof json !== "object") return {}; + delete json["0"]; // remove default preset entry + return json; + } catch (e) { + return {}; + } +} function B() { window.open(getURL("/settings"),"_self"); } var timeout; function showToast(text, error = false) { diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 910961ac22..f3a3b19e5f 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -35,40 +35,44 @@ if (loc) d.Sf.action = getURL('/settings/time'); } function loadPresets() { - try { - var p = localStorage.getItem("wledP"); - if (p) { - presets = JSON.parse(p); - } else { - fetch(getURL('/presets.json'), {method: 'get'}) - .then(res => res.ok ? res.json() : {}) - .then(json => { - delete json["0"]; // remove default preset entry - presets = json; - // Save to localStorage for future use - try { localStorage.setItem("wledP", JSON.stringify(presets)); } catch(e) {} - // run here because fetch is async - buildSortedPresetOptions(); - populateMacroPresets(); - }) - .catch(e => console.log("Failed to fetch presets:", e)); - } - } catch(e) {} - buildSortedPresetOptions(); + bSPO(); + rTOPO(); + rBPO(); + fetchPresetsJson().then(json => { + presets = json; + bSPO(); + pMP(); + rTOPO(); + rBPO(); + }); } - function buildSortedPresetOptions() { - var arr = Object.entries(presets); - arr.sort((a,b)=> parseInt(a[0]) - parseInt(b[0])); + function bSPO() { // buildSortedPresetOptions sortedPresetOptions = ''; - for (var p of arr) { - if (p[0]=="0") continue; - var id = parseInt(p[0]); + for (var p of Object.entries(presets)) { + var id = p[0]; var name = p[1].n || ("Preset " + id); - // Truncate long preset names to 20 chars and add ellipsis - var displayName = name.length > 20 ? name.substring(0, 19) + '…' : name; - sortedPresetOptions += ``; + sortedPresetOptions += ``; } } + function sPSV(sel, value, attrName) { // setPresetSelectValue + var v = (value === undefined || value === null || value === "") ? "0" : String(value); + sel.setAttribute(attrName, v); + sel.value = v; + if (sel.value === "") sel.value = "0"; + } + function rPS(sel, presetOpts, attrName) { // refreshPresetSelect + var currentVal = sel.value; + var initialVal = sel.getAttribute(attrName); + var val = currentVal; + if ((val === "" || val === "0") && initialVal !== null && initialVal !== "" && initialVal !== "0") { + val = initialVal; + } + if (val === "") val = "0"; + sel.innerHTML = presetOpts; + sel.value = val; + if (sel.value === "" && initialVal !== null && initialVal !== "") sel.value = initialVal; + if (sel.value === "") sel.value = "0"; + } function expand(o,i) { var t = gId("WD"+i); @@ -78,7 +82,8 @@ function Cs() { gId("cac").style.display=(gN("OL").checked)?"block":"none"; } function BTa() { - gId("TMT").innerHTML = ""; + timerCount = 0; + gId("TMT").innerHTML = "En.TypeHourMinute"; } function addTimerRow(hour, minute, preset, weekdays, monthStart, dayStart, monthEnd, dayEnd) { if (timerCount >= maxTimers) return; @@ -98,27 +103,7 @@ var dow = weekdays >> 1; var container = gId("TMT"); var hourVal = isSpecial ? 0 : hour; - var presetOpts = '' + sortedPresetOptions.replace(new RegExp(`value="${preset}"`, 'g'), `value="${preset}" selected`); - - var timerBlock = document.createElement('div'); - timerBlock.className = 'tb'; - - var timerMain = ` -
-
-
-
-
-
-
-
-
-
-
-
📅
-
-
- `; + var presetOpts = '' + sortedPresetOptions; var weekdayTable = ''; for (j=1;j<8;j++) weekdayTable += ``; @@ -130,15 +115,45 @@ for (j=0;j<12;j++) dateRange += ``; dateRange += ``; + var timerMain = ` + + + + + + + + `; + var timerExpanded = ` - + + + `; - timerBlock.innerHTML = timerMain + timerExpanded; - container.appendChild(timerBlock); + container.insertAdjacentHTML("beforeend", timerMain + timerExpanded); + var timerPresetSel = gId("T"+i); + sPSV(timerPresetSel, preset, "data-preset"); } function TT(i) { var sel = gId("TS"+i); @@ -165,22 +180,45 @@ } } function FC() { - populateMacroPresets(); + pMP(); } - function populateMacroPresets() { + function pMP() { // populateMacroPresets var presetOpts = '' + sortedPresetOptions; var fields = ['A0','A1','MC','MN']; for (var f of fields) { var inp = gN(f); if (!inp) continue; - var val = inp.value || 0; - var sel = document.createElement('select'); - sel.name = f; - sel.className = inp.className; - sel.required = inp.required; - sel.innerHTML = presetOpts; - sel.value = val; - inp.parentNode.replaceChild(sel, inp); + var val = inp.getAttribute("data-preset-value"); + if (val === null || val === "") val = inp.value; + if (inp.tagName === "SELECT") { + sPSV(inp, val, "data-preset-value"); + rPS(inp, presetOpts, "data-preset-value"); + } else { + var sel = document.createElement('select'); + sel.name = f; + sel.className = inp.className; + sel.required = inp.required; + sPSV(sel, val, "data-preset-value"); + rPS(sel, presetOpts, "data-preset-value"); + inp.parentNode.replaceChild(sel, inp); + } + } + } + function rTOPO() { // refreshTimerPresetOptions + var presetOpts = '' + sortedPresetOptions; + for (var i=0; i
- +
- +
- +
+
`; - container.appendChild(buttonBlock); + var buttonSels = buttonBlock.querySelectorAll("select"); + var buttonVals = [String(p), String(l), String(d)]; + for (var si=0; siTimer & Alexa Presets

Button Action Presets

-
MTWTFSS
>(j-1))&1?'checked':''}>
+ + + +
+
+ +
📅
+ +

+ +
- - - - - - - - - - -
push
switch
short
on->off
long
off->on
double
N/A
+
Analog Button setup

Time-Controlled Presets

-
+
+

diff --git a/wled00/data/style.css b/wled00/data/style.css index 691b9f78cb..72a66653ad 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -157,6 +157,9 @@ td { font-size:1.5rem; cursor:pointer } +#TMT table { + width: 100%; +} #msg { display: none; From 2679217abb45346705673d2989734c0a1417eff4 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 21:00:54 -0700 Subject: [PATCH 23/34] common --- wled00/data/common.js | 11 ++++++++--- wled00/data/settings_time.htm | 13 ++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index ef35730cb7..4ccc5d7d2d 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -93,9 +93,9 @@ function loadJS(FILE_URL, async = true, preGetV = undefined, postGetV = undefine // success event scE.addEventListener("load", () => { //console.log("File loaded"); - if (typeof preGetV === "function") preGetV(); - if (typeof GetV === "function") GetV(); - if (typeof postGetV === "function") postGetV(); + if (preGetV) preGetV(); + if (GetV) GetV(); + if (postGetV) postGetV(); }); // error event scE.addEventListener("error", (ev) => { @@ -138,6 +138,11 @@ async function fetchPresetsJson() { return {}; } } +async function loadPresets(callback) { + const json = await fetchPresetsJson(); + if (callback) callback(json); + return json; +} function B() { window.open(getURL("/settings"),"_self"); } var timeout; function showToast(text, error = false) { diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index f3a3b19e5f..1ba5c3f3e8 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -26,7 +26,7 @@ function S() { getLoc(); - loadPresets(); + loadPresets(onPresetsLoaded); loadJS(getURL('/settings/s.js?p=5'), false, ()=>{BTa();}, ()=>{ updLatLon(); Cs(); @@ -34,17 +34,12 @@ }); if (loc) d.Sf.action = getURL('/settings/time'); } - function loadPresets() { + function onPresetsLoaded(json) { + presets = json; bSPO(); + pMP(); rTOPO(); rBPO(); - fetchPresetsJson().then(json => { - presets = json; - bSPO(); - pMP(); - rTOPO(); - rBPO(); - }); } function bSPO() { // buildSortedPresetOptions sortedPresetOptions = ''; From cd24fe9139adca8c54976346d0a6918d7b24269b Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 21:19:02 -0700 Subject: [PATCH 24/34] dry preset loading --- wled00/data/common.js | 29 ++++++++++++++--------------- wled00/data/index.htm | 1 + wled00/data/index.js | 16 ---------------- wled00/data/settings_time.htm | 8 +++++++- 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index 4ccc5d7d2d..48e34c43cd 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -126,22 +126,21 @@ function getLoc() { } } function getURL(path) { return (loc ? locproto + "//" + locip : "") + path; } -async function fetchPresetsJson() { - try { - const res = await fetch(getURL('/presets.json'), {method: 'get'}); - if (!res.ok) return {}; - const json = await res.json(); - if (!json || typeof json !== "object") return {}; - delete json["0"]; // remove default preset entry - return json; - } catch (e) { - return {}; - } -} async function loadPresets(callback) { - const json = await fetchPresetsJson(); - if (callback) callback(json); - return json; + return new Promise((resolve) => { + fetch(getURL('/presets.json'), {method: 'get'}) + .then(res => res.status == "404" ? {"0":{}} : res.json()) + .then(json => { + if (typeof pJson !== "undefined") pJson = json; + if (callback) callback(json); + else if (typeof populatePresets === "function") populatePresets(); + resolve(json); + }) + .catch(() => { + if (typeof presetError === "function") presetError(false); + resolve(null); + }) + }); } function B() { window.open(getURL("/settings"),"_self"); } var timeout; diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 4d680cfbe2..54a08d426d 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -367,6 +367,7 @@ --> + diff --git a/wled00/data/index.js b/wled00/data/index.js index cd508e8642..791f7deff9 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -491,22 +491,6 @@ function restore(txt) { return false; } -async function loadPresets() { - return new Promise((resolve) => { - fetch(getURL('/presets.json'), {method: 'get'}) - .then(res => res.status=="404" ? {"0":{}} : res.json()) - .then(json => { - pJson = json; - populatePresets(); - resolve(); - }) - .catch(() => { - presetError(false); - resolve(); - }) - }); -} - async function loadPalettes(retry=0) { return new Promise((resolve) => { fetch(getURL('/json/palettes'), {method: 'get'}) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 1ba5c3f3e8..eb3b9f96e9 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -26,7 +26,7 @@ function S() { getLoc(); - loadPresets(onPresetsLoaded); + populatePresets(true); loadJS(getURL('/settings/s.js?p=5'), false, ()=>{BTa();}, ()=>{ updLatLon(); Cs(); @@ -34,8 +34,14 @@ }); if (loc) d.Sf.action = getURL('/settings/time'); } + function populatePresets(fromls) { + if (fromls) presets = JSON.parse(localStorage.getItem("wledP")); + if (!presets) {loadPresets(onPresetsLoaded); return;} + onPresetsLoaded(presets); + } function onPresetsLoaded(json) { presets = json; + delete presets["0"]; bSPO(); pMP(); rTOPO(); From 93ba3b3842b02260375019d8082371ac0fe990bb Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 21:22:31 -0700 Subject: [PATCH 25/34] revert missing const --- wled00/const.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wled00/const.h b/wled00/const.h index e6abd2b5db..6311bfe509 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -59,6 +59,7 @@ constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_C #define WLED_MAX_RMT_CHANNELS 0 // ESP8266 does not have RMT nor I2S #define WLED_MAX_I2S_CHANNELS 0 #define WLED_MAX_ANALOG_CHANNELS 5 + #define WLED_MAX_TIMERS 16 // reduced limit for ESP8266 due to memory constraints #define WLED_PLATFORM_ID 0 // used in UI to distinguish ESP types, needs a proper fix! #else #if !defined(LEDC_CHANNEL_MAX) || !defined(LEDC_SPEED_MODE_MAX) @@ -86,6 +87,7 @@ constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_C //#define WLED_MAX_ANALOG_CHANNELS 16 #define WLED_PLATFORM_ID 4 // used in UI to distinguish ESP type in UI, needs a proper fix! #endif + #define WLED_MAX_TIMERS 64 // maximum number of timers #define WLED_MAX_DIGITAL_CHANNELS (WLED_MAX_RMT_CHANNELS + WLED_MAX_I2S_CHANNELS) #endif // WLED_MAX_BUSSES was used to define the size of busses[] array which is no longer needed From 0a4df0bd4b4de2d88676abd1a01a01d059651b21 Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 21:49:55 -0700 Subject: [PATCH 26/34] update deep sleep usermod with new timer struct --- usermods/deep_sleep/deep_sleep.cpp | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/usermods/deep_sleep/deep_sleep.cpp b/usermods/deep_sleep/deep_sleep.cpp index cff40f86de..c110e562c6 100644 --- a/usermods/deep_sleep/deep_sleep.cpp +++ b/usermods/deep_sleep/deep_sleep.cpp @@ -89,28 +89,29 @@ class DeepSleepUsermod : public Usermod { int currentWeekday = weekdayMondayFirst(); // 1=Monday ... 7=Sunday int minDifference = INT_MAX; - for (uint8_t i = 0; i < 8; i++) { - // check if timer is enabled and date is in range, also wakes up if no macro is used - if ((timerWeekday[i] & 0x01) && isTodayInDateRange(((timerMonth[i] >> 4) & 0x0F), timerDay[i], timerMonth[i] & 0x0F, timerDayEnd[i])) { + for (size_t i = 0; i < timers.size(); i++) { + const Timer& t = timers[i]; + // only regular enabled timers with valid date range can be used for wake scheduling + if (!t.isEnabled() || !t.isRegular()) continue; + if (!isTodayInDateRange(t.monthStart, t.dayStart, t.monthEnd, t.dayEnd)) continue; - // if timer is enabled (bit0 of timerWeekday) and date is in range, check all weekdays it is set for - for (int dayOffset = 0; dayOffset < 7; dayOffset++) { - int checkWeekday = ((currentWeekday + dayOffset) % 7); // 1-7, check all weekdays starting from today - if (checkWeekday == 0) { - checkWeekday = 7; // sunday is 7 not 0 - } + // check all weekdays for the current timer, starting from today + for (int dayOffset = 0; dayOffset < 7; dayOffset++) { + int checkWeekday = (currentWeekday + dayOffset) % 7; // 1-7, check all weekdays starting from today + if (checkWeekday == 0) { + checkWeekday = 7; // sunday is 7 not 0 + } - int targetHour = timerHours[i]; - int targetMinute = timerMinutes[i]; - if ((timerWeekday[i] >> (checkWeekday)) & 0x01) { - if (dayOffset == 0 && (targetHour < currentHour || (targetHour == currentHour && targetMinute <= currentMinute))) - continue; // skip if time has already passed today + int targetHour = t.hour; + int targetMinute = t.minute; + if ((t.weekdays >> checkWeekday) & 0x01) { + if (dayOffset == 0 && (targetHour < currentHour || (targetHour == currentHour && targetMinute <= currentMinute))) + continue; // skip if time has already passed today - int timeDifference = calculateTimeDifference(currentHour, currentMinute, targetHour + (dayOffset * 24), targetMinute); - if (timeDifference < minDifference) { - minDifference = timeDifference; - wakeupPreset = timerMacro[i]; - } + int timeDifference = calculateTimeDifference(currentHour, currentMinute, targetHour + (dayOffset * 24), targetMinute); + if (timeDifference < minDifference) { + minDifference = timeDifference; + wakeupPreset = t.preset; } } } From fdc01f2f5dae896cf201726a3c4650448d21765c Mon Sep 17 00:00:00 2001 From: benjamw Date: Thu, 19 Feb 2026 21:56:41 -0700 Subject: [PATCH 27/34] tabs --- wled00/data/style.css | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/wled00/data/style.css b/wled00/data/style.css index 72a66653ad..0caf0949d1 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -1,5 +1,5 @@ html { - touch-action: manipulation; + touch-action: manipulation; } body { font-family: Verdana, sans-serif; @@ -35,7 +35,7 @@ button, .btn { color: #fff; font-family: Verdana, sans-serif; border: 0.3ch solid #333; - border-radius: 24px; + border-radius: 24px; display: inline-block; font-size: 20px; margin: 12px 8px 8px; @@ -166,32 +166,32 @@ td { } #toast { - opacity: 0; - background-color: #444; - border-radius: 5px; - bottom: 64px; - color: #fff; - font-size: 17px; - padding: 16px; - pointer-events: none; - position: fixed; - text-align: center; - z-index: 5; - transform: translateX(-50%); + opacity: 0; + background-color: #444; + border-radius: 5px; + bottom: 64px; + color: #fff; + font-size: 17px; + padding: 16px; + pointer-events: none; + position: fixed; + text-align: center; + z-index: 5; + transform: translateX(-50%); max-width: 90%; - left: 50%; + left: 50%; } #toast.show { - opacity: 1; - background-color: #264; - animation: fadein 0.5s, fadein 0.5s 2.5s reverse; + opacity: 1; + background-color: #264; + animation: fadein 0.5s, fadein 0.5s 2.5s reverse; } #toast.error { - opacity: 1; - background-color: #b21; - animation: fadein 0.5s; + opacity: 1; + background-color: #b21; + animation: fadein 0.5s; } @media screen and (max-width: 767px) { From 2bd27b88dc29c7970b322165deacc8131deb1e08 Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 20 Feb 2026 10:45:51 -0700 Subject: [PATCH 28/34] Revert "tabs" This reverts commit fdc01f2f5dae896cf201726a3c4650448d21765c. --- wled00/data/style.css | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/wled00/data/style.css b/wled00/data/style.css index 0caf0949d1..72a66653ad 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -1,5 +1,5 @@ html { - touch-action: manipulation; + touch-action: manipulation; } body { font-family: Verdana, sans-serif; @@ -35,7 +35,7 @@ button, .btn { color: #fff; font-family: Verdana, sans-serif; border: 0.3ch solid #333; - border-radius: 24px; + border-radius: 24px; display: inline-block; font-size: 20px; margin: 12px 8px 8px; @@ -166,32 +166,32 @@ td { } #toast { - opacity: 0; - background-color: #444; - border-radius: 5px; - bottom: 64px; - color: #fff; - font-size: 17px; - padding: 16px; - pointer-events: none; - position: fixed; - text-align: center; - z-index: 5; - transform: translateX(-50%); + opacity: 0; + background-color: #444; + border-radius: 5px; + bottom: 64px; + color: #fff; + font-size: 17px; + padding: 16px; + pointer-events: none; + position: fixed; + text-align: center; + z-index: 5; + transform: translateX(-50%); max-width: 90%; - left: 50%; + left: 50%; } #toast.show { - opacity: 1; - background-color: #264; - animation: fadein 0.5s, fadein 0.5s 2.5s reverse; + opacity: 1; + background-color: #264; + animation: fadein 0.5s, fadein 0.5s 2.5s reverse; } #toast.error { - opacity: 1; - background-color: #b21; - animation: fadein 0.5s; + opacity: 1; + background-color: #b21; + animation: fadein 0.5s; } @media screen and (max-width: 767px) { From 2060a6f0f80be2461a9fab0978f6d6fdb76e1099 Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 20 Feb 2026 10:46:16 -0700 Subject: [PATCH 29/34] remove unneeded clamp checks --- wled00/ntp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 74e4d119ed..0f9dc97845 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -564,13 +564,13 @@ void addTimer(uint8_t preset, uint8_t hour, int8_t minute, uint8_t weekdays, return; } } - if ((monthStart != 0 && (monthStart < 1 || monthStart > 12)) || - (monthEnd != 0 && (monthEnd < 1 || monthEnd > 12))) { + if ((monthStart != 0 && monthStart > 12) || + (monthEnd != 0 && monthEnd > 12)) { DEBUG_PRINTLN(F("Timer: Invalid month range")); return; } - if ((dayStart != 0 && (dayStart < 1 || dayStart > 31)) || - (dayEnd != 0 && (dayEnd < 1 || dayEnd > 31))) { + if ((dayStart != 0 && dayStart > 31) || + (dayEnd != 0 && dayEnd > 31)) { DEBUG_PRINTLN(F("Timer: Invalid day range")); return; } From 40dde137beaff29683c83f99d9a9743a9a8b0581 Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 20 Feb 2026 10:48:49 -0700 Subject: [PATCH 30/34] leave index alone --- wled00/data/index.htm | 1 - wled00/data/index.js | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 54a08d426d..4d680cfbe2 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -367,7 +367,6 @@ --> - diff --git a/wled00/data/index.js b/wled00/data/index.js index 791f7deff9..cd508e8642 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -491,6 +491,22 @@ function restore(txt) { return false; } +async function loadPresets() { + return new Promise((resolve) => { + fetch(getURL('/presets.json'), {method: 'get'}) + .then(res => res.status=="404" ? {"0":{}} : res.json()) + .then(json => { + pJson = json; + populatePresets(); + resolve(); + }) + .catch(() => { + presetError(false); + resolve(); + }) + }); +} + async function loadPalettes(retry=0) { return new Promise((resolve) => { fetch(getURL('/json/palettes'), {method: 'get'}) From d6a437997846fe36aa38f364722a598a7deb9f9c Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 20 Feb 2026 22:20:58 -0700 Subject: [PATCH 31/34] remove useless check --- wled00/data/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index 48e34c43cd..38b792b848 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -94,7 +94,7 @@ function loadJS(FILE_URL, async = true, preGetV = undefined, postGetV = undefine scE.addEventListener("load", () => { //console.log("File loaded"); if (preGetV) preGetV(); - if (GetV) GetV(); + GetV(); if (postGetV) postGetV(); }); // error event From d34eb4341894557d43b3e33ada2e0ee41315fbc7 Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 20 Feb 2026 22:55:11 -0700 Subject: [PATCH 32/34] fix up await functions --- wled00/data/common.js | 16 ---------------- wled00/data/settings_time.htm | 22 ++++++++++++++-------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index 38b792b848..e12ddf2df6 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -126,22 +126,6 @@ function getLoc() { } } function getURL(path) { return (loc ? locproto + "//" + locip : "") + path; } -async function loadPresets(callback) { - return new Promise((resolve) => { - fetch(getURL('/presets.json'), {method: 'get'}) - .then(res => res.status == "404" ? {"0":{}} : res.json()) - .then(json => { - if (typeof pJson !== "undefined") pJson = json; - if (callback) callback(json); - else if (typeof populatePresets === "function") populatePresets(); - resolve(json); - }) - .catch(() => { - if (typeof presetError === "function") presetError(false); - resolve(null); - }) - }); -} function B() { window.open(getURL("/settings"),"_self"); } var timeout; function showToast(text, error = false) { diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index eb3b9f96e9..74a786666e 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -30,14 +30,23 @@ loadJS(getURL('/settings/s.js?p=5'), false, ()=>{BTa();}, ()=>{ updLatLon(); Cs(); - FC(); }); if (loc) d.Sf.action = getURL('/settings/time'); } - function populatePresets(fromls) { - if (fromls) presets = JSON.parse(localStorage.getItem("wledP")); - if (!presets) {loadPresets(onPresetsLoaded); return;} - onPresetsLoaded(presets); + async function populatePresets(fromls) { + let json = null; + if (fromls) json = JSON.parse(localStorage.getItem("wledP")); + if (!json) json = await loadPresets(); + if (json) onPresetsLoaded(json); + } + async function loadPresets() { + try { + const res = await fetch(getURL('/presets.json'), {method: 'get'}); + return res.status == "404" ? {"0": {}} : await res.json(); + } catch (e) { + console.error("Failed to load presets:", e); + return null; + } } function onPresetsLoaded(json) { presets = json; @@ -180,9 +189,6 @@ if (min.value < 0 || min.value > 59) min.value = 0; } } - function FC() { - pMP(); - } function pMP() { // populateMacroPresets var presetOpts = '' + sortedPresetOptions; var fields = ['A0','A1','MC','MN']; From f7495e637d0d7916c3e3dc15648e7856bdeda2b9 Mon Sep 17 00:00:00 2001 From: benjamw Date: Sun, 22 Feb 2026 13:42:28 -0700 Subject: [PATCH 33/34] only fetch localstorage --- wled00/data/settings_time.htm | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 74a786666e..fb1b2a60f6 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -33,20 +33,23 @@ }); if (loc) d.Sf.action = getURL('/settings/time'); } - async function populatePresets(fromls) { + function populatePresets(fromls) { let json = null; - if (fromls) json = JSON.parse(localStorage.getItem("wledP")); - if (!json) json = await loadPresets(); - if (json) onPresetsLoaded(json); - } - async function loadPresets() { - try { - const res = await fetch(getURL('/presets.json'), {method: 'get'}); - return res.status == "404" ? {"0": {}} : await res.json(); - } catch (e) { - console.error("Failed to load presets:", e); - return null; + if (fromls) { + try { + json = JSON.parse(localStorage.getItem("wledP")); + } catch (e) {} + } + + if (!json) { + showPresetWarning(); + return; } + + onPresetsLoaded(json); + } + function showPresetWarning() { + showToast("Please visit the main UI first to load presets", true); } function onPresetsLoaded(json) { presets = json; From eba81ee67bcde0977d6bc44f80e6d400adee6d40 Mon Sep 17 00:00:00 2001 From: benjamw Date: Fri, 6 Mar 2026 16:24:41 -0700 Subject: [PATCH 34/34] inline single line function --- wled00/data/settings_time.htm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index fb1b2a60f6..ab2c4a7fc0 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -42,15 +42,12 @@ } if (!json) { - showPresetWarning(); + showToast("Please visit the main UI first to load presets", true); return; } onPresetsLoaded(json); } - function showPresetWarning() { - showToast("Please visit the main UI first to load presets", true); - } function onPresetsLoaded(json) { presets = json; delete presets["0"];