From c03ced5539561a9468fdf9f5eaf3970702a46418 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 24 Sep 2025 19:23:01 +0000
Subject: [PATCH 1/9] Initial plan
From 07f408e53d480c7cd772d8700fb13c6435835b5b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 24 Sep 2025 19:34:46 +0000
Subject: [PATCH 2/9] Implement comprehensive error logging system with
user-accessible error log
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/const.h | 17 ++++
wled00/data/index.js | 187 +++++++++++++++++++++++++++++++++++--------
2 files changed, 169 insertions(+), 35 deletions(-)
diff --git a/wled00/const.h b/wled00/const.h
index 8891dfcaee..01ddee4f16 100644
--- a/wled00/const.h
+++ b/wled00/const.h
@@ -439,6 +439,23 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit");
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
+// Additional error types for better user feedback
+#define ERR_NORAM_BUS 33 // Not enough RAM for bus allocation
+#define ERR_NORAM_SEG 34 // Not enough RAM for segment allocation
+#define ERR_NORAM_TRANS 35 // Not enough RAM for transition effects
+#define ERR_PIN_CONFLICT 36 // Pin assignment conflict detected
+#define ERR_PIN_INVALID 37 // Invalid pin number for this platform
+#define ERR_CONFIG_LOAD 38 // Configuration loading failed
+#define ERR_CONFIG_SAVE 39 // Configuration saving failed
+
+// Warning types (starting at 100 as requested)
+#define WARN_LOW_MEMORY 100 // Low memory warning
+#define WARN_HIGH_TEMP 101 // Temperature approaching limits
+#define WARN_LOW_VOLTAGE 102 // Voltage below optimal range
+#define WARN_HIGH_CURRENT 103 // Current approaching limits
+#define WARN_WIFI_WEAK 104 // Weak WiFi signal
+#define WARN_FS_SPACE 105 // Filesystem space running low
+
// Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
#define NL_MODE_FADE 1 //Fade to target brightness gradually
diff --git a/wled00/data/index.js b/wled00/data/index.js
index 2514f03fb1..db5e8ac4e1 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -26,6 +26,8 @@ var pmt = 1, pmtLS = 0, pmtLast = 0;
var lastinfo = {};
var isM = false, mw = 0, mh=0;
var ws, wsRpt=0;
+var errorLog = []; // Store last 5 errors/warnings
+var hasUnreadErrors = false;
var cfg = {
theme:{base:"dark", bg:{url:"", rnd: false, rndGrayscale: false, rndBlur: false}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
@@ -384,6 +386,131 @@ function inforow(key, val, unit = "")
return `
${key} ${val}${unit} `;
}
+function getErrorMessage(errorCode) {
+ switch (errorCode) {
+ case 1: return "Operation denied by current settings";
+ case 2: return "Cannot process request while client is active";
+ case 3: return "JSON buffer is locked, try again in a moment";
+ case 4: return "Feature not implemented on this version";
+ case 7: return "Insufficient RAM to allocate pixel buffer";
+ case 8: return "Not enough RAM available for effect processing";
+ case 9: return "JSON parsing failed - data may be too large";
+ case 10: return "Could not initialize filesystem - check partition";
+ case 11: return "Not enough space to save preset to filesystem";
+ case 12: return "Requested preset does not exist";
+ case 13: return "IR configuration file 'ir.json' not found";
+ case 14: return "Remote configuration file 'remote.json' not found";
+ case 19: return "An unspecified filesystem error occurred";
+ case 30: return "Temperature sensor reading above safe threshold";
+ case 31: return "Current sensor reading above safe threshold";
+ case 32: return "Voltage sensor reading below safe threshold";
+ case 33: return "Insufficient RAM to allocate LED bus";
+ case 34: return "Insufficient RAM to allocate segment data";
+ case 35: return "Insufficient RAM for transition effects";
+ case 36: return "Pin assignment conflict detected";
+ case 37: return "Invalid pin number for this platform";
+ case 38: return "Failed to load configuration from filesystem";
+ case 39: return "Failed to save configuration to filesystem";
+ case 100: return "Memory usage is approaching limits";
+ case 101: return "Temperature is approaching safe limits";
+ case 102: return "Voltage is below optimal operating range";
+ case 103: return "Current draw is approaching safe limits";
+ case 104: return "WiFi signal strength is poor";
+ case 105: return "Filesystem space is running low";
+ default: return `Unknown error code ${errorCode}`;
+ }
+}
+
+function addToErrorLog(errorCode, timestamp = null) {
+ if (!timestamp) timestamp = Date.now();
+
+ const errorEntry = {
+ code: errorCode,
+ message: getErrorMessage(errorCode),
+ timestamp: timestamp,
+ isWarning: errorCode >= 100
+ };
+
+ // Add to beginning of array
+ errorLog.unshift(errorEntry);
+
+ // Keep only last 5 entries
+ if (errorLog.length > 5) {
+ errorLog = errorLog.slice(0, 5);
+ }
+
+ hasUnreadErrors = true;
+ updateInfoButtonIcon();
+}
+
+function updateInfoButtonIcon() {
+ const infoBtn = gId('buttonI');
+ const icon = infoBtn.querySelector('i');
+ if (hasUnreadErrors) {
+ // Change to red exclamation mark icon
+ icon.innerHTML = ''; // Exclamation mark
+ icon.style.color = 'var(--c-r)';
+ } else {
+ // Reset to normal info icon
+ icon.innerHTML = ''; // Info icon
+ icon.style.color = '';
+ }
+}
+
+function clearErrorLog() {
+ errorLog = [];
+ hasUnreadErrors = false;
+ updateInfoButtonIcon();
+ const errorArea = gId('errorLogArea');
+ if (errorArea) {
+ errorArea.style.display = 'none';
+ gId('errorLogContent').innerHTML = '';
+ }
+}
+
+function generateErrorLogHtml() {
+ if (errorLog.length === 0) return '';
+
+ let html = '';
+ for (let i = 0; i < errorLog.length; i++) {
+ const entry = errorLog[i];
+ const timeStr = new Date(entry.timestamp).toLocaleTimeString();
+ const icon = entry.isWarning ? '⚠' : '🚫'; // Warning triangle or error circle
+ const color = entry.isWarning ? 'var(--c-y)' : 'var(--c-r)';
+
+ html += `
+
+ ${icon} ${entry.isWarning ? 'Warning' : 'Error'} ${entry.code} - ${timeStr}
+
+
+ ${entry.message}
+
+
`;
+ }
+
+ html += `
+
+ Clear Log
+
+
`;
+
+ return html;
+}
+
+function toggleErrorLog() {
+ const content = gId('errorLogContent');
+ const button = content.previousElementSibling;
+
+ if (content.style.display === 'none') {
+ content.style.display = 'block';
+ content.innerHTML = generateErrorLogHtml();
+ button.innerHTML = ' Hide Error Log';
+ } else {
+ content.style.display = 'none';
+ button.innerHTML = ` Show Error Log (${errorLog.length})`;
+ }
+}
+
function getLowestUnusedP()
{
var l = 1;
@@ -746,6 +873,19 @@ ${inforow("Flash size",i.flash," MB")}
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")}
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
`;
+
+ // Add error log section if there are any errors
+ if (errorLog.length > 0) {
+ cn += `
+
+ Show Error Log (${errorLog.length})
+
+
+ ${generateErrorLogHtml()}
+
+
`;
+ }
+
gId('kv').innerHTML = cn;
// update all sliders in Info
d.querySelectorAll('#kv .sliderdisplay').forEach((sd,i) => {
@@ -1518,40 +1658,12 @@ function readState(s,command=false)
gId('checkO3').checked = !(!i.o3);
if (s.error && s.error != 0) {
- var errstr = "";
- switch (s.error) {
- case 1:
- errstr = "Denied!";
- break;
- case 3:
- errstr = "Buffer locked!";
- break;
- case 7:
- errstr = "No RAM for buffer!";
- break;
- case 8:
- errstr = "Effect RAM depleted!";
- break;
- case 9:
- errstr = "JSON parsing error!";
- break;
- case 10:
- errstr = "Could not mount filesystem!";
- break;
- case 11:
- errstr = "Not enough space to save preset!";
- break;
- case 12:
- errstr = "Preset not found.";
- break;
- case 13:
- errstr = "Missing ir.json.";
- break;
- case 19:
- errstr = "A filesystem error has occured.";
- break;
- }
- showToast('Error ' + s.error + ": " + errstr, true);
+ // Add to error log for detailed tracking
+ addToErrorLog(s.error);
+
+ // Keep showing toast for immediate feedback (simplified message)
+ const shortMessage = s.error >= 100 ? 'Warning' : 'Error';
+ showToast(`${shortMessage} ${s.error}`, true);
}
selectedPal = i.pal;
@@ -1846,7 +1958,12 @@ function toggleInfo()
if (isNodes) toggleNodes();
if (isLv && isM) toggleLiveview();
isInfo = !isInfo;
- if (isInfo) requestJson();
+ if (isInfo) {
+ requestJson();
+ // Mark errors as read when info panel is opened
+ hasUnreadErrors = false;
+ updateInfoButtonIcon();
+ }
gId('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)";
gId('buttonI').className = (isInfo) ? "active":"";
}
From cc827c82350e3f4170e2f66b4ac4b2d2a1de64b1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Sep 2025 10:26:41 +0000
Subject: [PATCH 3/9] Fix error logging system based on feedback - restore
detailed toasts, fix positioning and icon
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.htm | 6 ++
wled00/data/index.js | 131 ++++++++++++++++++++++++++++++------------
2 files changed, 100 insertions(+), 37 deletions(-)
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index 22f1987e93..c075932f17 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -332,6 +332,12 @@
Update WLED
Reboot WLED
+
Made with ❤︎ by Aircoookie and the WLED community
diff --git a/wled00/data/index.js b/wled00/data/index.js
index db5e8ac4e1..b5db7081f2 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -448,7 +448,7 @@ function updateInfoButtonIcon() {
const icon = infoBtn.querySelector('i');
if (hasUnreadErrors) {
// Change to red exclamation mark icon
- icon.innerHTML = ''; // Exclamation mark
+ icon.innerHTML = ''; // Use add/warning icon
icon.style.color = 'var(--c-r)';
} else {
// Reset to normal info icon
@@ -464,7 +464,6 @@ function clearErrorLog() {
const errorArea = gId('errorLogArea');
if (errorArea) {
errorArea.style.display = 'none';
- gId('errorLogContent').innerHTML = '';
}
}
@@ -488,29 +487,9 @@ function generateErrorLogHtml() {
`;
}
- html += `
-
- Clear Log
-
-
`;
-
return html;
}
-function toggleErrorLog() {
- const content = gId('errorLogContent');
- const button = content.previousElementSibling;
-
- if (content.style.display === 'none') {
- content.style.display = 'block';
- content.innerHTML = generateErrorLogHtml();
- button.innerHTML = ' Hide Error Log';
- } else {
- content.style.display = 'none';
- button.innerHTML = ` Show Error Log (${errorLog.length})`;
- }
-}
-
function getLowestUnusedP()
{
var l = 1;
@@ -873,20 +852,17 @@ ${inforow("Flash size",i.flash," MB")}
${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")}
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
`;
-
- // Add error log section if there are any errors
- if (errorLog.length > 0) {
- cn += `
-
- Show Error Log (${errorLog.length})
-
-
- ${generateErrorLogHtml()}
-
-
`;
- }
gId('kv').innerHTML = cn;
+
+ // Update error log area visibility and content
+ const errorArea = gId('errorLogArea');
+ if (errorLog.length > 0) {
+ errorArea.style.display = 'block';
+ gId('errorLogContent').innerHTML = generateErrorLogHtml();
+ } else {
+ errorArea.style.display = 'none';
+ }
// update all sliders in Info
d.querySelectorAll('#kv .sliderdisplay').forEach((sd,i) => {
let s = sd.previousElementSibling;
@@ -1661,9 +1637,90 @@ function readState(s,command=false)
// Add to error log for detailed tracking
addToErrorLog(s.error);
- // Keep showing toast for immediate feedback (simplified message)
- const shortMessage = s.error >= 100 ? 'Warning' : 'Error';
- showToast(`${shortMessage} ${s.error}`, true);
+ // Show detailed toast message as before
+ var errstr = "";
+ switch (s.error) {
+ case 1:
+ errstr = "Denied!";
+ break;
+ case 3:
+ errstr = "Buffer locked!";
+ break;
+ case 7:
+ errstr = "No RAM for buffer!";
+ break;
+ case 8:
+ errstr = "Effect RAM depleted!";
+ break;
+ case 9:
+ errstr = "JSON parsing error!";
+ break;
+ case 10:
+ errstr = "Could not mount filesystem!";
+ break;
+ case 11:
+ errstr = "Not enough space to save preset!";
+ break;
+ case 12:
+ errstr = "Preset not found.";
+ break;
+ case 13:
+ errstr = "Missing ir.json.";
+ break;
+ case 19:
+ errstr = "A filesystem error has occured.";
+ break;
+ case 30:
+ errstr = "Overtemperature!";
+ break;
+ case 31:
+ errstr = "Overcurrent!";
+ break;
+ case 32:
+ errstr = "Undervoltage!";
+ break;
+ case 33:
+ errstr = "No RAM for bus!";
+ break;
+ case 34:
+ errstr = "No RAM for segment!";
+ break;
+ case 35:
+ errstr = "No RAM for transitions!";
+ break;
+ case 36:
+ errstr = "Pin conflict!";
+ break;
+ case 37:
+ errstr = "Invalid pin!";
+ break;
+ case 38:
+ errstr = "Config load failed!";
+ break;
+ case 39:
+ errstr = "Config save failed!";
+ break;
+ case 100:
+ errstr = "Low memory!";
+ break;
+ case 101:
+ errstr = "High temperature!";
+ break;
+ case 102:
+ errstr = "Low voltage!";
+ break;
+ case 103:
+ errstr = "High current!";
+ break;
+ case 104:
+ errstr = "Weak WiFi!";
+ break;
+ case 105:
+ errstr = "Low disk space!";
+ break;
+ }
+ const prefix = s.error >= 100 ? 'Warning' : 'Error';
+ showToast(`${prefix} ${s.error}: ${errstr}`, true);
}
selectedPal = i.pal;
From 61b11e185c06e5aa03da43e79799ccf7842f0930 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 28 Sep 2025 06:32:01 +0000
Subject: [PATCH 4/9] Implement server-side error logging system with
client-side timestamp calculation
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.htm | 12 ++--
wled00/data/index.js | 155 ++++++++++++++++--------------------------
wled00/fcn_declare.h | 4 ++
wled00/json.cpp | 28 +++++++-
wled00/util.cpp | 19 ++++++
wled00/wled.h | 14 ++++
6 files changed, 127 insertions(+), 105 deletions(-)
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index c075932f17..3b92d971e5 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -325,6 +325,12 @@
+
Loading...
Refresh
@@ -332,12 +338,6 @@
Update WLED
Reboot WLED
-
Made with ❤︎ by Aircoookie and the WLED community
diff --git a/wled00/data/index.js b/wled00/data/index.js
index b5db7081f2..b9955ea3e4 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -457,14 +457,58 @@ function updateInfoButtonIcon() {
}
}
-function clearErrorLog() {
+function handleServerErrorLog(serverErrors, serverTime) {
+ // Clear client-side log and replace with server data
errorLog = [];
hasUnreadErrors = false;
- updateInfoButtonIcon();
- const errorArea = gId('errorLogArea');
- if (errorArea) {
- errorArea.style.display = 'none';
+
+ for (let i = 0; i < serverErrors.length; i++) {
+ const serverEntry = serverErrors[i];
+ // Calculate absolute timestamp using server time and error timestamp
+ const absoluteTime = Date.now() - (serverTime - serverEntry.t);
+
+ const errorEntry = {
+ code: serverEntry.c,
+ message: getErrorMessage(serverEntry.c),
+ timestamp: absoluteTime,
+ isWarning: serverEntry.c >= 100,
+ tag1: serverEntry.t1 || 0,
+ tag2: serverEntry.t2 || 0,
+ tag3: serverEntry.t3 || 0
+ };
+
+ errorLog.push(errorEntry);
+ }
+
+ if (errorLog.length > 0) {
+ hasUnreadErrors = true;
}
+
+ updateInfoButtonIcon();
+}
+
+function clearErrorLog() {
+ // Send clear command to server
+ fetch(getURL('/json/state'), {
+ method: 'post',
+ body: JSON.stringify({clearErrorLog: true}),
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(res => {
+ // Clear local state
+ errorLog = [];
+ hasUnreadErrors = false;
+ updateInfoButtonIcon();
+ const errorArea = gId('errorLogArea');
+ if (errorArea) {
+ errorArea.style.display = 'none';
+ }
+ })
+ .catch((error) => {
+ console.log('Error clearing log:', error);
+ });
}
function generateErrorLogHtml() {
@@ -474,16 +518,11 @@ function generateErrorLogHtml() {
for (let i = 0; i < errorLog.length; i++) {
const entry = errorLog[i];
const timeStr = new Date(entry.timestamp).toLocaleTimeString();
- const icon = entry.isWarning ? '⚠' : '🚫'; // Warning triangle or error circle
+ const prefix = entry.isWarning ? 'Warning' : 'Error';
const color = entry.isWarning ? 'var(--c-y)' : 'var(--c-r)';
- html += `
-
- ${icon} ${entry.isWarning ? 'Warning' : 'Error'} ${entry.code} - ${timeStr}
-
-
- ${entry.message}
-
+ html += `
+ ${prefix} ${entry.code} - ${timeStr}: ${entry.message}
`;
}
@@ -1636,91 +1675,11 @@ function readState(s,command=false)
if (s.error && s.error != 0) {
// Add to error log for detailed tracking
addToErrorLog(s.error);
-
- // Show detailed toast message as before
- var errstr = "";
- switch (s.error) {
- case 1:
- errstr = "Denied!";
- break;
- case 3:
- errstr = "Buffer locked!";
- break;
- case 7:
- errstr = "No RAM for buffer!";
- break;
- case 8:
- errstr = "Effect RAM depleted!";
- break;
- case 9:
- errstr = "JSON parsing error!";
- break;
- case 10:
- errstr = "Could not mount filesystem!";
- break;
- case 11:
- errstr = "Not enough space to save preset!";
- break;
- case 12:
- errstr = "Preset not found.";
- break;
- case 13:
- errstr = "Missing ir.json.";
- break;
- case 19:
- errstr = "A filesystem error has occured.";
- break;
- case 30:
- errstr = "Overtemperature!";
- break;
- case 31:
- errstr = "Overcurrent!";
- break;
- case 32:
- errstr = "Undervoltage!";
- break;
- case 33:
- errstr = "No RAM for bus!";
- break;
- case 34:
- errstr = "No RAM for segment!";
- break;
- case 35:
- errstr = "No RAM for transitions!";
- break;
- case 36:
- errstr = "Pin conflict!";
- break;
- case 37:
- errstr = "Invalid pin!";
- break;
- case 38:
- errstr = "Config load failed!";
- break;
- case 39:
- errstr = "Config save failed!";
- break;
- case 100:
- errstr = "Low memory!";
- break;
- case 101:
- errstr = "High temperature!";
- break;
- case 102:
- errstr = "Low voltage!";
- break;
- case 103:
- errstr = "High current!";
- break;
- case 104:
- errstr = "Weak WiFi!";
- break;
- case 105:
- errstr = "Low disk space!";
- break;
- }
- const prefix = s.error >= 100 ? 'Warning' : 'Error';
- showToast(`${prefix} ${s.error}: ${errstr}`, true);
+ }
+
+ // Handle server-side error log
+ if (s.errorLog && s.errorLogTime) {
+ handleServerErrorLog(s.errorLog, s.errorLogTime);
}
selectedPal = i.pal;
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index 1d81655d6d..4cc2f7999a 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -555,4 +555,8 @@ void sendDataWs(AsyncWebSocketClient * client = nullptr);
void XML_response(Print& dest);
void getSettingsJS(byte subPage, Print& dest);
+//util.cpp - error logging
+void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0);
+void clearErrorLog();
+
#endif
diff --git a/wled00/json.cpp b/wled00/json.cpp
index d2b771c590..391a6251db 100644
--- a/wled00/json.cpp
+++ b/wled00/json.cpp
@@ -367,6 +367,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
#if defined(WLED_DEBUG) && defined(WLED_DEBUG_HOST)
netDebugEnabled = root[F("debug")] | netDebugEnabled;
#endif
+
+ // Handle clear error log command
+ if (root[F("clearErrorLog")]) {
+ clearErrorLog();
+ }
bool onBefore = bri;
getVal(root["bri"], bri);
@@ -639,7 +644,28 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
}
if (!forPreset) {
- if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;} //prevent error message to persist on screen
+ if (errorFlag) {
+ root[F("error")] = errorFlag;
+ addToErrorLog(errorFlag); // Add to error log
+ errorFlag = ERR_NONE; // Reset error flag
+ }
+
+ // Add error log to JSON response
+ if (errorLogCount > 0) {
+ JsonArray errors = root.createNestedArray(F("errorLog"));
+ byte startIdx = (errorLogIndex + ERROR_LOG_SIZE - errorLogCount) % ERROR_LOG_SIZE;
+
+ for (byte i = 0; i < errorLogCount; i++) {
+ byte idx = (startIdx + i) % ERROR_LOG_SIZE;
+ JsonObject err = errors.createNestedObject();
+ err[F("t")] = errorLog[idx].timestamp;
+ err[F("c")] = errorLog[idx].errorCode;
+ err[F("t1")] = errorLog[idx].tag1;
+ err[F("t2")] = errorLog[idx].tag2;
+ err[F("t3")] = errorLog[idx].tag3;
+ }
+ root[F("errorLogTime")] = millis(); // Current time for client calculations
+ }
root["ps"] = (currentPreset > 0) ? currentPreset : -1;
root[F("pl")] = currentPlaylist;
diff --git a/wled00/util.cpp b/wled00/util.cpp
index 8aaaf34cab..e02892de8e 100644
--- a/wled00/util.cpp
+++ b/wled00/util.cpp
@@ -1124,4 +1124,23 @@ uint8_t perlin8(uint16_t x, uint16_t y) {
uint8_t perlin8(uint16_t x, uint16_t y, uint16_t z) {
return (((perlin3D_raw((uint32_t)x << 8, (uint32_t)y << 8, (uint32_t)z << 8, true) * 2015) >> 10) + 33168) >> 8; //scale to 16 bit, offset, then scale to 8bit
+}
+
+// Error logging functions
+void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0) {
+ errorLog[errorLogIndex].timestamp = millis();
+ errorLog[errorLogIndex].errorCode = errorCode;
+ errorLog[errorLogIndex].tag1 = tag1;
+ errorLog[errorLogIndex].tag2 = tag2;
+ errorLog[errorLogIndex].tag3 = tag3;
+
+ errorLogIndex = (errorLogIndex + 1) % ERROR_LOG_SIZE;
+ if (errorLogCount < ERROR_LOG_SIZE) {
+ errorLogCount++;
+ }
+}
+
+void clearErrorLog() {
+ errorLogIndex = 0;
+ errorLogCount = 0;
}
\ No newline at end of file
diff --git a/wled00/wled.h b/wled00/wled.h
index a783986a87..fb549ba389 100644
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -889,6 +889,20 @@ WLED_GLOBAL byte currentPreset _INIT(0);
WLED_GLOBAL byte errorFlag _INIT(0);
+// Error logging system
+struct ErrorLogEntry {
+ unsigned long timestamp; // millis() when error occurred
+ byte errorCode; // error number (8bit)
+ byte tag1; // future use tag 1
+ byte tag2; // future use tag 2
+ byte tag3; // future use tag 3
+};
+
+#define ERROR_LOG_SIZE 5
+WLED_GLOBAL ErrorLogEntry errorLog[ERROR_LOG_SIZE];
+WLED_GLOBAL byte errorLogIndex _INIT(0);
+WLED_GLOBAL byte errorLogCount _INIT(0);
+
WLED_GLOBAL String messageHead, messageSub;
WLED_GLOBAL byte optionType;
From 756697ae7821d391577a681639e1def195e355c6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 28 Sep 2025 11:00:20 +0000
Subject: [PATCH 5/9] Improve error log formatting - remove colored lines,
center align area, 24h timestamps, larger font
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.htm | 4 ++--
wled00/data/index.js | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index 3b92d971e5..4ace10479c 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -325,8 +325,8 @@
-
-
+
+
Clear Log
diff --git a/wled00/data/index.js b/wled00/data/index.js
index b9955ea3e4..e1d89fd989 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -517,12 +517,12 @@ function generateErrorLogHtml() {
let html = '';
for (let i = 0; i < errorLog.length; i++) {
const entry = errorLog[i];
- const timeStr = new Date(entry.timestamp).toLocaleTimeString();
+ // Use 24h format without seconds
+ const timeStr = new Date(entry.timestamp).toLocaleTimeString([], {hour12: false, hour: '2-digit', minute: '2-digit'});
const prefix = entry.isWarning ? 'Warning' : 'Error';
- const color = entry.isWarning ? 'var(--c-y)' : 'var(--c-r)';
- html += `
-
${prefix} ${entry.code} - ${timeStr}: ${entry.message}
+ html += `
+ ${timeStr} ${prefix} ${entry.code}: ${entry.message}
`;
}
From 4b6df49e90148a4312e89ebea213a7a76666f21f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 28 Sep 2025 13:17:00 +0000
Subject: [PATCH 6/9] Refactor error logging system - move from global to local
scope, use shorter JSON command
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.js | 2 +-
wled00/fcn_declare.h | 2 ++
wled00/json.cpp | 19 +++++++++----------
wled00/util.cpp | 26 +++++++++++++++++++++++++-
wled00/wled.h | 14 --------------
5 files changed, 37 insertions(+), 26 deletions(-)
diff --git a/wled00/data/index.js b/wled00/data/index.js
index e1d89fd989..9bc2bca525 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -491,7 +491,7 @@ function clearErrorLog() {
// Send clear command to server
fetch(getURL('/json/state'), {
method: 'post',
- body: JSON.stringify({clearErrorLog: true}),
+ body: JSON.stringify({clrErrLog: true}),
headers: {
'Content-Type': 'application/json'
}
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index 4cc2f7999a..f8cb10bd18 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -558,5 +558,7 @@ void getSettingsJS(byte subPage, Print& dest);
//util.cpp - error logging
void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0);
void clearErrorLog();
+byte getErrorLogCount();
+const struct ErrorLogEntry& getErrorLogEntry(byte index);
#endif
diff --git a/wled00/json.cpp b/wled00/json.cpp
index 391a6251db..fd3296b14b 100644
--- a/wled00/json.cpp
+++ b/wled00/json.cpp
@@ -369,7 +369,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
#endif
// Handle clear error log command
- if (root[F("clearErrorLog")]) {
+ if (root[F("clrErrLog")]) {
clearErrorLog();
}
@@ -651,18 +651,17 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
}
// Add error log to JSON response
- if (errorLogCount > 0) {
+ if (getErrorLogCount() > 0) {
JsonArray errors = root.createNestedArray(F("errorLog"));
- byte startIdx = (errorLogIndex + ERROR_LOG_SIZE - errorLogCount) % ERROR_LOG_SIZE;
- for (byte i = 0; i < errorLogCount; i++) {
- byte idx = (startIdx + i) % ERROR_LOG_SIZE;
+ for (byte i = 0; i < getErrorLogCount(); i++) {
+ const ErrorLogEntry& entry = getErrorLogEntry(i);
JsonObject err = errors.createNestedObject();
- err[F("t")] = errorLog[idx].timestamp;
- err[F("c")] = errorLog[idx].errorCode;
- err[F("t1")] = errorLog[idx].tag1;
- err[F("t2")] = errorLog[idx].tag2;
- err[F("t3")] = errorLog[idx].tag3;
+ err[F("t")] = entry.timestamp;
+ err[F("c")] = entry.errorCode;
+ err[F("t1")] = entry.tag1;
+ err[F("t2")] = entry.tag2;
+ err[F("t3")] = entry.tag3;
}
root[F("errorLogTime")] = millis(); // Current time for client calculations
}
diff --git a/wled00/util.cpp b/wled00/util.cpp
index e02892de8e..e5c5e02627 100644
--- a/wled00/util.cpp
+++ b/wled00/util.cpp
@@ -1126,8 +1126,22 @@ uint8_t perlin8(uint16_t x, uint16_t y, uint16_t z) {
return (((perlin3D_raw((uint32_t)x << 8, (uint32_t)y << 8, (uint32_t)z << 8, true) * 2015) >> 10) + 33168) >> 8; //scale to 16 bit, offset, then scale to 8bit
}
+// Error logging system
+struct ErrorLogEntry {
+ unsigned long timestamp; // millis() when error occurred
+ byte errorCode; // error number (8bit)
+ byte tag1; // future use tag 1
+ byte tag2; // future use tag 2
+ byte tag3; // future use tag 3
+};
+
+#define ERROR_LOG_SIZE 5
+static ErrorLogEntry errorLog[ERROR_LOG_SIZE];
+static byte errorLogIndex = 0;
+static byte errorLogCount = 0;
+
// Error logging functions
-void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0) {
+void addToErrorLog(byte errorCode, byte tag1, byte tag2, byte tag3) {
errorLog[errorLogIndex].timestamp = millis();
errorLog[errorLogIndex].errorCode = errorCode;
errorLog[errorLogIndex].tag1 = tag1;
@@ -1143,4 +1157,14 @@ void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0)
void clearErrorLog() {
errorLogIndex = 0;
errorLogCount = 0;
+}
+
+// Helper functions to read error log
+byte getErrorLogCount() {
+ return errorLogCount;
+}
+
+const ErrorLogEntry& getErrorLogEntry(byte index) {
+ byte actualIndex = (errorLogIndex + ERROR_LOG_SIZE - errorLogCount + index) % ERROR_LOG_SIZE;
+ return errorLog[actualIndex];
}
\ No newline at end of file
diff --git a/wled00/wled.h b/wled00/wled.h
index fb549ba389..a783986a87 100644
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -889,20 +889,6 @@ WLED_GLOBAL byte currentPreset _INIT(0);
WLED_GLOBAL byte errorFlag _INIT(0);
-// Error logging system
-struct ErrorLogEntry {
- unsigned long timestamp; // millis() when error occurred
- byte errorCode; // error number (8bit)
- byte tag1; // future use tag 1
- byte tag2; // future use tag 2
- byte tag3; // future use tag 3
-};
-
-#define ERROR_LOG_SIZE 5
-WLED_GLOBAL ErrorLogEntry errorLog[ERROR_LOG_SIZE];
-WLED_GLOBAL byte errorLogIndex _INIT(0);
-WLED_GLOBAL byte errorLogCount _INIT(0);
-
WLED_GLOBAL String messageHead, messageSub;
WLED_GLOBAL byte optionType;
From 7ce7c93bd7a148ec43e10797a387551f59bc75d0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 28 Sep 2025 13:25:33 +0000
Subject: [PATCH 7/9] Update error log styling - full width and text wrapping
enabled
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.htm | 2 +-
wled00/data/index.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index 4ace10479c..f604d54038 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -325,7 +325,7 @@
-
+
Clear Log
diff --git a/wled00/data/index.js b/wled00/data/index.js
index 9bc2bca525..976d553bdd 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -521,7 +521,7 @@ function generateErrorLogHtml() {
const timeStr = new Date(entry.timestamp).toLocaleTimeString([], {hour12: false, hour: '2-digit', minute: '2-digit'});
const prefix = entry.isWarning ? 'Warning' : 'Error';
- html += `
+ html += `
${timeStr} ${prefix} ${entry.code}: ${entry.message}
`;
}
From 7d79c52e20e18b1f4bceef3690396892106ca783 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 28 Sep 2025 14:00:47 +0000
Subject: [PATCH 8/9] Add error log title and restore color-coded error
messages
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.htm | 1 +
wled00/data/index.js | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/wled00/data/index.htm b/wled00/data/index.htm
index f604d54038..9e8910eb28 100644
--- a/wled00/data/index.htm
+++ b/wled00/data/index.htm
@@ -326,6 +326,7 @@
+
Error Log
Clear Log
diff --git a/wled00/data/index.js b/wled00/data/index.js
index 976d553bdd..0b60b08e81 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -520,8 +520,9 @@ function generateErrorLogHtml() {
// Use 24h format without seconds
const timeStr = new Date(entry.timestamp).toLocaleTimeString([], {hour12: false, hour: '2-digit', minute: '2-digit'});
const prefix = entry.isWarning ? 'Warning' : 'Error';
+ const color = entry.isWarning ? 'var(--c-y)' : 'var(--c-r)';
- html += `
+ html += `
${timeStr} ${prefix} ${entry.code}: ${entry.message}
`;
}
From 7f6778a1268b6dbc4f5c9ab5461677a7a2d82748 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Oct 2025 05:28:15 +0000
Subject: [PATCH 9/9] Add support for custom error message strings in
ErrorLogEntry
Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
---
wled00/data/index.js | 4 +++-
wled00/fcn_declare.h | 2 +-
wled00/json.cpp | 4 ++++
wled00/util.cpp | 28 +++++++++++++++++++++++++++-
4 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/wled00/data/index.js b/wled00/data/index.js
index 0b60b08e81..b5c65bf6f8 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -469,8 +469,10 @@ function handleServerErrorLog(serverErrors, serverTime) {
const errorEntry = {
code: serverEntry.c,
- message: getErrorMessage(serverEntry.c),
+ // Use custom message if provided, otherwise use error code lookup
+ message: serverEntry.m ? serverEntry.m : getErrorMessage(serverEntry.c),
timestamp: absoluteTime,
+ // If custom message provided, determine warning/error based on code range
isWarning: serverEntry.c >= 100,
tag1: serverEntry.t1 || 0,
tag2: serverEntry.t2 || 0,
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index f8cb10bd18..e9a3b14150 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -556,7 +556,7 @@ void XML_response(Print& dest);
void getSettingsJS(byte subPage, Print& dest);
//util.cpp - error logging
-void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0);
+void addToErrorLog(byte errorCode, byte tag1 = 0, byte tag2 = 0, byte tag3 = 0, const char* customMessage = nullptr);
void clearErrorLog();
byte getErrorLogCount();
const struct ErrorLogEntry& getErrorLogEntry(byte index);
diff --git a/wled00/json.cpp b/wled00/json.cpp
index fd3296b14b..06106dd95f 100644
--- a/wled00/json.cpp
+++ b/wled00/json.cpp
@@ -662,6 +662,10 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
err[F("t1")] = entry.tag1;
err[F("t2")] = entry.tag2;
err[F("t3")] = entry.tag3;
+ // Add custom message if present
+ if (entry.customMessage != nullptr) {
+ err[F("m")] = entry.customMessage;
+ }
}
root[F("errorLogTime")] = millis(); // Current time for client calculations
}
diff --git a/wled00/util.cpp b/wled00/util.cpp
index e5c5e02627..6b7c163cb8 100644
--- a/wled00/util.cpp
+++ b/wled00/util.cpp
@@ -1133,6 +1133,7 @@ struct ErrorLogEntry {
byte tag1; // future use tag 1
byte tag2; // future use tag 2
byte tag3; // future use tag 3
+ char* customMessage; // optional custom message string (nullptr if not used)
};
#define ERROR_LOG_SIZE 5
@@ -1141,13 +1142,30 @@ static byte errorLogIndex = 0;
static byte errorLogCount = 0;
// Error logging functions
-void addToErrorLog(byte errorCode, byte tag1, byte tag2, byte tag3) {
+void addToErrorLog(byte errorCode, byte tag1, byte tag2, byte tag3, const char* customMessage) {
+ // Free existing custom message if present
+ if (errorLog[errorLogIndex].customMessage != nullptr) {
+ delete[] errorLog[errorLogIndex].customMessage;
+ errorLog[errorLogIndex].customMessage = nullptr;
+ }
+
errorLog[errorLogIndex].timestamp = millis();
errorLog[errorLogIndex].errorCode = errorCode;
errorLog[errorLogIndex].tag1 = tag1;
errorLog[errorLogIndex].tag2 = tag2;
errorLog[errorLogIndex].tag3 = tag3;
+ // Copy custom message if provided
+ if (customMessage != nullptr) {
+ size_t len = strlen(customMessage);
+ errorLog[errorLogIndex].customMessage = new char[len + 1];
+ if (errorLog[errorLogIndex].customMessage != nullptr) {
+ strcpy(errorLog[errorLogIndex].customMessage, customMessage);
+ }
+ } else {
+ errorLog[errorLogIndex].customMessage = nullptr;
+ }
+
errorLogIndex = (errorLogIndex + 1) % ERROR_LOG_SIZE;
if (errorLogCount < ERROR_LOG_SIZE) {
errorLogCount++;
@@ -1155,6 +1173,14 @@ void addToErrorLog(byte errorCode, byte tag1, byte tag2, byte tag3) {
}
void clearErrorLog() {
+ // Free all custom message strings
+ for (byte i = 0; i < ERROR_LOG_SIZE; i++) {
+ if (errorLog[i].customMessage != nullptr) {
+ delete[] errorLog[i].customMessage;
+ errorLog[i].customMessage = nullptr;
+ }
+ }
+
errorLogIndex = 0;
errorLogCount = 0;
}