From fc84725ae4c2c0a10f1e9164ffdba2c3596e903f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Dec 2025 09:58:52 +0000 Subject: [PATCH 01/16] Initial plan From 99e07432814179cb2a78e7897467aea53932d4de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Dec 2025 10:06:30 +0000 Subject: [PATCH 02/16] Fix Hub75 shown incorrectly in LED output dropdowns Call hideHub75() after dynamically adding new LED outputs to ensure Hub75 options are removed when Hub75 support is not compiled in. Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com> --- wled00/data/settings_leds.htm | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 1bde6fbc..487f3385 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -464,6 +464,7 @@ ${i+1}:

Auto-calculate white channel from RGB:
 
`; f.insertAdjacentHTML("beforeend", cn); + hideHub75(); // remove Hub75 options if not supported } if (n==-1) { o[--i].remove();--i; From 381208b81f3b128df806df304262c71612f32c55 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:53:34 +0000 Subject: [PATCH 03/16] Fix Hub75 removal breaking Hub75-enabled builds Only call hideHub75() when Hub75 is actually disabled. Track with window.hub75Hidden flag set when hideHub75() is first called by backend. Co-authored-by: softhack007 <91616163+softhack007@users.noreply.github.com> --- wled00/data/settings_leds.htm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 487f3385..c2775ac4 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -17,6 +17,7 @@ function gId(n){return d.getElementById(n);} function hideNoIR(){gId("irOnOff2").style.display="none";} //WLEDMM function hideHub75() { + window.hub75Hidden = true; // Track that Hub75 should be hidden var s = d.getElementsByTagName("select"); for (i=0; i
Auto-calculate white channel from RGB:
  `; f.insertAdjacentHTML("beforeend", cn); - hideHub75(); // remove Hub75 options if not supported + if (window.hub75Hidden) hideHub75(); // remove Hub75 options if not supported } if (n==-1) { o[--i].remove();--i; From 1210881bd8442850d6c1af57cbe7eb5b3c8c3cae Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:00:53 +0100 Subject: [PATCH 04/16] reduce risk of crashes (stack smashing) due calls to notify() The function uses a UDP buffer of ~1200 bytes on stack, which is only needed when actually sending out notifications. -> separate activation checks and actual sending into two functions, to reduce stack pressure. --- wled00/udp.cpp | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 0d403aab..bd2c37b1 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -10,23 +10,9 @@ #define UDP_IN_MAXSIZE 1472 #define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times -void notify(byte callMode, bool followUp) -{ - if (!udpConnected) return; - if (!syncGroups) return; - switch (callMode) - { - case CALL_MODE_INIT: return; - case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break; - case CALL_MODE_BUTTON: if (!notifyButton) return; break; - case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break; - case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break; - case CALL_MODE_HUE: if (!notifyHue) return; break; - case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break; - case CALL_MODE_ALEXA: if (!notifyAlexa) return; break; - default: return; - } - byte udpOut[WLEDPACKETSIZE]; +static void do_notify(byte callMode, bool followUp) { // WLEDMM split into two functions, to avoid stack smashing - do_notify needs 1200 bytes on stack + // DEBUG_PRINTF("[%8u %s]\tnotify(%d, %s)\tmin stack %d\n", millis(), pcTaskGetTaskName(NULL), callMode, followUp?"true ":"false", uxTaskGetStackHighWaterMark(NULL)); + byte udpOut[WLEDPACKETSIZE] = {0}; Segment& mainseg = strip.getMainSegment(); udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol udpOut[1] = callMode; @@ -150,6 +136,27 @@ void notify(byte callMode, bool followUp) notificationCount = followUp ? notificationCount + 1 : 0; } +// WLEDMM wrapper function to avoid stack smashing - do_notify needs 1200 bytes on stack, but its not actually sending anything on most notify() calls +void notify(byte callMode, bool followUp) +{ + if (!udpConnected) return; + if (!syncGroups) return; + switch (callMode) + { + case CALL_MODE_INIT: return; + case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break; + case CALL_MODE_BUTTON: if (!notifyButton) return; break; + case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break; + case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break; + case CALL_MODE_HUE: if (!notifyHue) return; break; + case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break; + case CALL_MODE_ALEXA: if (!notifyAlexa) return; break; + default: return; + } + do_notify(callMode, followUp); +} + + // WLEDMM cache current main segment: updated in realtimeLock, reset in exitRealtime, used in setRealTimePixel static Segment* theMainSeg = nullptr; static int theMainSegLength = 0; @@ -736,6 +743,7 @@ void refreshNodeList() void sendSysInfoUDP() { if (!udp2Connected) return; + // DEBUG_PRINTF("[%8u %s]\tsendSysInfoUDP()\tmin stack %d\n", millis(), pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); IPAddress ip = Network.localIP(); if (!ip || ip == IPAddress(255,255,255,255)) ip = IPAddress(4,3,2,1); From 1d686d7807f7550bae74cc682d3bbdb58290ad1a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:49:53 +0100 Subject: [PATCH 05/16] leds 2D preview: better color accuracy * replace "jumpy" color enhancement with a smooth function * slightly increase size of preview pixels --- wled00/data/peek.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wled00/data/peek.js b/wled00/data/peek.js index 24ee7ee7..7578bcf6 100644 --- a/wled00/data/peek.js +++ b/wled00/data/peek.js @@ -30,13 +30,15 @@ function peek(c) { ctx.clearRect(0, 0, c.width, c.height); //WLEDMM function colorAmp(color) { if (color == 0) return 0; - return 25+225*color/255; + //return color; // no enhancement + //return 25+225*color/255; // legacy WLEDMM. problem: strong jump from 0 to 25 -> wrong colors + return Math.sqrt(color/255) * 255; // Square root provides gentle and jump-free enhancement of lower brightness pixels } //WLEDMM in range 55 - 205 for (y=0.5;y 0.45 ctx.fill(); } i+=3; From b17819e2cefe2d76389ad842223631a3f4e6bd43 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:47:13 +0100 Subject: [PATCH 06/16] better trails for PS Fireworks --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9a1a6100..a9641fb8 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -9455,7 +9455,7 @@ uint16_t mode_particlefireworks(void) { return FRAMETIME; } #undef NUMBEROFSOURCES -static const char _data_FX_MODE_PARTICLEFIREWORKS[] PROGMEM = "PS Fireworks@Launches,Explosion Size,Fuse,Blur,Gravity,Cylinder,Ground,Fast;;!;2;pal=11,ix=200,sx=180,c1=196,c2=0,c3=10,o3=1"; +static const char _data_FX_MODE_PARTICLEFIREWORKS[] PROGMEM = "PS Fireworks@Launches,Explosion Size,Fuse,Blur,Gravity,Cylinder,Ground,Fast;;!;2;pal=11,ix=200,sx=180,c1=196,c2=220,c3=10,o3=1"; /* Particle Volcano From a47bbfe05b362c5978a17f0764aa334b1781ab9c Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 2 Feb 2026 23:06:03 +0100 Subject: [PATCH 07/16] spots effect improvements * use native 32bit types (similar to upstream) * avoids gaps on left/right side of strip, by using higher accuracy for zoneLength * prevent overflow on "s" * fix wrongly named slider in "spots fade" --- wled00/FX.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a9641fb8..9a98eee4 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -3015,21 +3015,22 @@ uint16_t spots_base(uint16_t threshold) if (SEGLEN == 1) return mode_oops(); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); - uint16_t maxZones = SEGLEN >> 2; - uint16_t zones = 1 + ((SEGMENT.intensity * maxZones) >> 8); - uint16_t zoneLen = SEGLEN / zones; - uint16_t offset = (SEGLEN - zones * zoneLen) >> 1; + unsigned maxZones = max(1, SEGLEN >> 2); // WLEDMM prevent "0 zones" + unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8); + unsigned zoneLen = SEGLEN / zones; + unsigned zoneLen8 = zones < 8 ? zoneLen * 8 : SEGLEN / (zones >> 3); // WLEDMM zoneLength * 8 -> avoids gaps at right/left sides + unsigned offset = (uint32_t(SEGLEN) - ((zones * zoneLen8)>>3)) >> 1; - for (int z = 0; z < zones; z++) + for (unsigned z = 0; z < zones; z++) { - uint16_t pos = offset + z * zoneLen; - for (int i = 0; i < zoneLen; i++) + unsigned pos = offset +((z * zoneLen8)>>3); + for (unsigned i = 0; i < zoneLen; i++) { - uint16_t wave = triwave16((i * 0xFFFF) / zoneLen); + unsigned wave = triwave16((i * 0xFFFF) / zoneLen); if (wave > threshold) { - uint16_t index = 0 + pos + i; - uint8_t s = (wave - threshold)*255 / (0xFFFF - threshold); - SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255-s)); + int index = pos + i; + unsigned s = ((wave - threshold)*255 / (0xFFFF - threshold)) & 0xFF; // WLEDMM prevent overflow + SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s))); } } } @@ -3054,7 +3055,7 @@ uint16_t mode_spots_fade() uint16_t tr = (t >> 1) + (t >> 2); return spots_base(tr); } -static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!"; +static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Speed,Width,,,,,Overlay;!,!;!"; //each needs 12 bytes From dea91bc2ab2bc0168bb32d1109f742b64599b3b9 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:33:52 +0100 Subject: [PATCH 08/16] spots effect bugfix * use named constants for fixed point scaling * remove buggy "SEGLEN / (zones >>3)" shortcut * align code with upstream --- wled00/FX.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9a98eee4..e9f57850 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -3012,24 +3012,28 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr uint16_t spots_base(uint16_t threshold) { - if (SEGLEN == 1) return mode_oops(); + if (SEGLEN <= 1) return mode_oops(); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); - unsigned maxZones = max(1, SEGLEN >> 2); // WLEDMM prevent "0 zones" - unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8); - unsigned zoneLen = SEGLEN / zones; - unsigned zoneLen8 = zones < 8 ? zoneLen * 8 : SEGLEN / (zones >> 3); // WLEDMM zoneLength * 8 -> avoids gaps at right/left sides - unsigned offset = (uint32_t(SEGLEN) - ((zones * zoneLen8)>>3)) >> 1; + // constants for fixed point scaling + constexpr uint8_t ZONELEN_FP_SHIFT = 3; + constexpr uint32_t ZONELEN_FP_SCALE = 1U << ZONELEN_FP_SHIFT; + + unsigned maxZones = max(1, SEGLEN >> 2); // prevents "0 zones" + unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8); + unsigned zoneLen = uint32_t(SEGLEN) / zones; + unsigned zoneLen8 = (uint32_t(SEGLEN) * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixedโ€‘point) -> avoids gaps at right/left sides + unsigned offset = (uint32_t(SEGLEN) - ((zones * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1; for (unsigned z = 0; z < zones; z++) { - unsigned pos = offset +((z * zoneLen8)>>3); + unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT); for (unsigned i = 0; i < zoneLen; i++) { unsigned wave = triwave16((i * 0xFFFF) / zoneLen); if (wave > threshold) { int index = pos + i; - unsigned s = ((wave - threshold)*255 / (0xFFFF - threshold)) & 0xFF; // WLEDMM prevent overflow + unsigned s = ((wave - threshold)*255 / (0xFFFF - threshold)) & 0xFF; // & 0xFF prevents overflow in next line SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s))); } } From 5eab1e7cece2fd2dd87a47e198ba475c3de64177 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:25:13 +0100 Subject: [PATCH 09/16] adding esp32_4MB_V4_S buildenv without HUB75 driver this build might work better for users with I2S microphone, because the HUB75 driver can interfere with the I2S driver. --- platformio.ini | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index d32b7917..af3b5857 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,6 +78,7 @@ default_envs = esp32_pico_4MB_V4_S ;; PICO D4 board esp32_4MB_V4_S_HUB75 ;; esp32 4MB - HUB75 supported esp32_4MB_V4_HUB75_forum ;; esp32 4MB - HUB75 supported (forum pinout) + esp32_4MB_V4_S ;; without HUB75 driver - might work better with I2S microphones esp32_4MB_M_eth ;; esp32 4MB with ethernet support esp32_4MB_V4_S_eth ;; esp32 4MB "V4" build with ethernet support ; esp32_4MB_PSRAM_REV3_S ;; WROVER-E experimental, optimized for WROVER-E with "revision3" chip @@ -1852,8 +1853,35 @@ lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compila ; RAM: [=== ] 25.5% (used 83396 bytes from 327680 bytes) ; Flash: [==========] 98.2% (used 1543949 bytes from 1572864 bytes) -[env:esp32_4MB_V4_S] ;; legacy alias -extends = env:esp32_4MB_V4_S_HUB75 +[env:esp32_4MB_V4_S] ;; without HUB75 driver - might work better with I2S microphones +extends = esp32_4MB_V4_S_base +;; board_build.partitions = ${esp32.default_partitions} ;; compatible with upstream +build_unflags = ${esp32_4MB_V4_S_base.build_unflags} + ${common_mm.DMXin_build_flags} ;; exceeds flash size limits +build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} + -D WLED_RELEASE_NAME=esp32_4MB_V4_S + -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET + -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup + -D WLEDMM_FASTPATH ; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. + -D WLEDMM_SAVE_FLASH + -D WLED_DISABLE_LOXONE + -D WLED_DISABLE_ALEXA + -D WLED_DISABLE_HUESYNC + -D WLED_DISABLE_MQTT + -D WLED_DISABLE_INFRARED + -D WLED_DISABLE_ESPNOW ;; might help in case of WiFi connectivity problems + -D WLED_ENABLE_PIXELFORGE + -D WLEDMM_SAVE_FLASH + ; -D WLED_DEBUG + ; -D SR_DEBUG + ; -D MIC_LOGGER + ;; -D SR_DMTYPE=254 ;; HUB75 driver needs the I2S unit - this sets AR default mode to 'Network Receive Only' to prevent driver conflicts. + ;; -D WLED_DISABLE_PARTICLESYSTEM1D + ;; -D WLED_DISABLE_PARTICLESYSTEM2D +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} +lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation + ${common_mm.DMXin_lib_ignore} + ${common_mm.HUB75_lib_ignore} ; standard MM build for classic esp32; HUB75 not included [env:esp32_4MB_V4_M] From 7fd23932e421b980b7a3827e2434bb3715f20633 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:14:54 +0100 Subject: [PATCH 10/16] (minor) fix for apChannel reset to 1 instead of 6 spotted by @dedehai in https://github.com/wled/WLED/pull/5332 --- wled00/cfg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 069b303a..653da685 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -67,7 +67,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { //int ap_pskl = ap[F("pskl")]; CJSON(apChannel, ap[F("chan")]); - if (apChannel > 13 || apChannel < 1) apChannel = 1; + if (apChannel > 13 || apChannel < 1) apChannel = 6; // reset to default if invalid CJSON(apHide, ap[F("hide")]); if (apHide > 1) apHide = 1; From 30ce4c55bae55de3c753e71053f5477a12dd6a1f Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Feb 2026 23:11:53 +0100 Subject: [PATCH 11/16] remove HUB75 driver from esp32_16MB_V4 builds due to known conflicts with I2S audio input --- platformio.ini | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index af3b5857..3eb79632 100644 --- a/platformio.ini +++ b/platformio.ini @@ -83,8 +83,10 @@ default_envs = esp32_4MB_V4_S_eth ;; esp32 4MB "V4" build with ethernet support ; esp32_4MB_PSRAM_REV3_S ;; WROVER-E experimental, optimized for WROVER-E with "revision3" chip esp32_4MB_PSRAM_S ;; esp32 WROVER with PSRAM; HUB75 supported - esp32_16MB_V4_S ;; esp32 16MB - HUB75 supported, optimized for speed - esp32_16MB_V4_M ;; esp32 16MB - HUB75 supported + esp32_16MB_V4_S ;; esp32 16MB - without HUB75 driver, optimized for speed + esp32_16MB_V4_M ;; esp32 16MB - without HUB75 driver + esp32_16MB_V4_S_HUB75 ;; esp32 16MB - HUB75 supported, optimized for speed + ; esp32_16MB_V4_M_HUB75 ;; esp32 16MB - HUB75 supported esp32_16MB_V4_M_debug ;; esp32 16MB - for out-of-the-box debugging ;; esp32S3_4MB_S ;; experimental, for HD-WF2 (HUB75 supported) @@ -2040,13 +2042,13 @@ board_build.flash_mode = qio ; (dio = dual i/o; more compatible than qio = quad ; Flash: [==========] 98.1% (used 1863653 bytes from 1900544 bytes) ;; V4 build for 16MB flash, optimized for speed; HUB75 supported -[env:esp32_16MB_V4_S] +[env:esp32_16MB_V4_S_HUB75] extends = esp32_4MB_V4_S_base build_unflags = ${esp32_4MB_V4_S_base.build_unflags} ${Speed_Flags.build_unflags} ;; to override -Os build_flags = ${esp32_4MB_V4_S_base.esp32_build_flags} ${Speed_Flags.build_flags_V4} ;; optimize for speed instead of size - -D WLED_RELEASE_NAME=esp32_16MB_V4_S + -D WLED_RELEASE_NAME=esp32_16MB_V4_S_HUB75 -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup -D WLEDMM_FASTPATH ; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. @@ -2069,11 +2071,27 @@ board_build.partitions = ${esp32.extreme_partitions} ;; WLED extended for 16MB f ; RAM: [== ] 23.7% (used 77704 bytes from 327680 bytes) ; Flash: [======== ] 84.4% (used 1770341 bytes from 2097152 bytes) +;; same as above, but without HUB75 driver - better for I2S audio input +[env:esp32_16MB_V4_S] +extends = env:esp32_16MB_V4_S_HUB75 +build_unflags = ${env:esp32_16MB_V4_S_HUB75.build_unflags} + -D WLED_RELEASE_NAME=esp32_16MB_V4_S_HUB75 + -D WLED_ENABLE_HUB75MATRIX ;; remove HUB driver + -D WLEDMM_SLOWPATH ;; not necessary without HUB75 + -D SR_DMTYPE=254 ;; not necessary without HUB75 +build_flags = ${env:esp32_16MB_V4_S_HUB75.build_flags} + -D WLED_RELEASE_NAME=esp32_16MB_V4_S +lib_deps = ${esp32_4MB_V4_S_base.esp32_lib_deps} + ${common_mm.animartrix_lib_deps} +lib_ignore = + ${common_mm.HUB75_lib_ignore} ;; remove HUB driver dependancy + + ; compiled with ESP-IDF 4.4.1; HUB75 included (may have PIN conflicts) -[env:esp32_16MB_V4_M] +[env:esp32_16MB_V4_M_HUB75] extends = esp32_4MB_V4_M_base build_flags = ${esp32_4MB_V4_M_base.esp32_build_flags} - -D WLED_RELEASE_NAME=esp32_16MB_V4_M + -D WLED_RELEASE_NAME=esp32_16MB_V4_M_HUB75 -D WLED_WATCHDOG_TIMEOUT=0 #-D WLED_DISABLE_BROWNOUT_DET -D ARDUINO_USB_CDC_ON_BOOT=0 ; needed for arduino-esp32 >=2.0.4; avoids errors on startup ;; -D WLED_ENABLE_DMX ;; disabled because it does not work with ESP-IDF 4.4.x (buggy driver in SparkFunDMX) @@ -2098,6 +2116,22 @@ board_build.partitions = ${esp32.extreme_partitions} ;; WLED extended for 16MB f ; RAM: [=== ] 25.7% (used 84104 bytes from 327680 bytes) ; Flash: [======== ] 80.7% (used 1692269 bytes from 2097152 bytes) +;; same as above, but without HUB75 driver - better for I2S audio input +[env:esp32_16MB_V4_M] +extends = env:esp32_16MB_V4_M_HUB75 +build_unflags = ${env:esp32_16MB_V4_M_HUB75.build_unflags} + -D WLED_RELEASE_NAME=esp32_16MB_V4_M_HUB75 + -D WLED_ENABLE_HUB75MATRIX ;; remove HUB driver + -D WLEDMM_SLOWPATH ;; not necessary without HUB75 + -D SR_DMTYPE=254 ;; not necessary without HUB75 +build_flags = ${env:esp32_16MB_V4_M_HUB75.build_flags} + -D WLED_RELEASE_NAME=esp32_16MB_V4_M +lib_deps = ${esp32_4MB_V4_M_base.esp32_lib_deps} + ${common_mm.animartrix_lib_deps} +lib_ignore = + ${common_mm.HUB75_lib_ignore} ;; remove HUB driver dependancy + + [env:esp32_16MB_V4_M_debug] extends = esp32_4MB_V4_M_base build_unflags = ${common.build_unflags} From fd079d61058d57c030018da2a907b36380f11f12 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Feb 2026 22:19:42 +0100 Subject: [PATCH 12/16] add HUB75 and DMX pins to usermods pin dropdown these pins were wrongly shown as "available", because the are not stored in the cfg.json part related to LEDs settings. --- wled00/data/settings_um.htm | 2 ++ wled00/xml.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index d0dd98f3..e6766d1f 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -269,6 +269,8 @@ // console.log("pinPost option", c, c.value, d.ro_gpio.includes(c.value)); for (let j=0; j max_gpio if (c.value > d.max_gpio) { select.removeChild(c); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 71f3340f..8abb6ee6 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -287,6 +287,30 @@ void appendGPIOinfo() { char a_pins[64] = { '\0' }; // fix warning: output 45 bytes into a destination of size 30 snprintf(a_pins, 64, "d.a_pins=[%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d];", pinManager.getADCPin(PM_ADC1, 0), pinManager.getADCPin(PM_ADC1, 1), pinManager.getADCPin(PM_ADC1, 2), pinManager.getADCPin(PM_ADC1, 3), pinManager.getADCPin(PM_ADC1, 4), pinManager.getADCPin(PM_ADC1, 5), pinManager.getADCPin(PM_ADC1, 6), pinManager.getADCPin(PM_ADC1, 7), pinManager.getADCPin(PM_ADC1, 8), pinManager.getADCPin(PM_ADC1, 9), pinManager.getADCPin(PM_ADC1, 10)); oappend(a_pins); + + // WLEDMM add HUB75 pins, as they are not stored directly in cfg.json + strcpy(ro_gpio, "d.h_pins=["); // WLEDMM we re-use this array, instead of creating an addition one; 140 bytes is more than enough for 14 pins. + bool isFirstHub = true; + for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { + if ((pinManager.isPinOk(pinNr)) && (pinManager.getPinOwner(pinNr) == PinOwner::HUB75)) { + sprintf(pinString, "%s%d", isFirstHub?"":",", pinNr); + strcat(ro_gpio, pinString); isFirstHub = false; + } + } + oappend(ro_gpio); + oappend(SET_F("];")); + + // WLEDMM same procedure for DMX pins + strcpy(ro_gpio, "d.x_pins=["); // WLEDMM we re-use this array, instead of creating an addition one; 140 bytes is more than enough for max 4 pins. + isFirstHub = true; + for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { + if ((pinManager.isPinOk(pinNr)) && (pinManager.getPinOwner(pinNr) == PinOwner::DMX || pinManager.getPinOwner(pinNr) == PinOwner::DMX_INPUT)) { + sprintf(pinString, "%s%d", isFirstHub?"":",", pinNr); + strcat(ro_gpio, pinString); isFirstHub = false; + } + } + oappend(ro_gpio); + oappend(SET_F("];")); } //get values for settings form in javascript From 53c396ecb16538279ccaed3a1c92d781de81b136 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Feb 2026 22:42:43 +0100 Subject: [PATCH 13/16] styling move "Ax" label slightly to the right, "DMX " doesn't need extra space --- wled00/data/settings_um.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index e6766d1f..8389bac8 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -270,7 +270,7 @@ for (let j=0; j max_gpio if (c.value > d.max_gpio) { select.removeChild(c); @@ -280,7 +280,7 @@ //https://www.javascripttutorial.net/javascript-dom/javascript-remove-items-from-a-select-conditionally/ if (c.text.length <= 4) c.text += " ๐ŸŸข"; //2 digit number space and โผ/โŽŒ. If no reserved/read only/other um, then pin can be freely used (green) for (let jj=0; jj Date: Wed, 4 Feb 2026 22:55:19 +0100 Subject: [PATCH 14/16] initialize new pin arrays --- wled00/data/settings_um.htm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index 8389bac8..a9e6809f 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -10,6 +10,8 @@ d.um_p = []; d.rsvd = []; d.ro_gpio = []; + d.h_pins = []; + d.x_pins = []; var umCfg = {}; var pins = [], pinO = [], owner; var loc = false, locip; From d591ff8ab809db4d9d615b26dc9ca01b675e1193 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Feb 2026 23:01:15 +0100 Subject: [PATCH 15/16] variable renamed for clarity isFirstHub => isFirstPin --- wled00/xml.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 8abb6ee6..2015952e 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -290,11 +290,11 @@ void appendGPIOinfo() { // WLEDMM add HUB75 pins, as they are not stored directly in cfg.json strcpy(ro_gpio, "d.h_pins=["); // WLEDMM we re-use this array, instead of creating an addition one; 140 bytes is more than enough for 14 pins. - bool isFirstHub = true; + bool isFirstPin = true; for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { if ((pinManager.isPinOk(pinNr)) && (pinManager.getPinOwner(pinNr) == PinOwner::HUB75)) { - sprintf(pinString, "%s%d", isFirstHub?"":",", pinNr); - strcat(ro_gpio, pinString); isFirstHub = false; + sprintf(pinString, "%s%d", isFirstPin ? "" : ",", pinNr); + strcat(ro_gpio, pinString); isFirstPin = false; } } oappend(ro_gpio); @@ -302,11 +302,11 @@ void appendGPIOinfo() { // WLEDMM same procedure for DMX pins strcpy(ro_gpio, "d.x_pins=["); // WLEDMM we re-use this array, instead of creating an addition one; 140 bytes is more than enough for max 4 pins. - isFirstHub = true; + isFirstPin = true; for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { if ((pinManager.isPinOk(pinNr)) && (pinManager.getPinOwner(pinNr) == PinOwner::DMX || pinManager.getPinOwner(pinNr) == PinOwner::DMX_INPUT)) { - sprintf(pinString, "%s%d", isFirstHub?"":",", pinNr); - strcat(ro_gpio, pinString); isFirstHub = false; + sprintf(pinString, "%s%d", isFirstPin ? "" : ",", pinNr); + strcat(ro_gpio, pinString); isFirstPin = false; } } oappend(ro_gpio); From b7d81e7fca1506966a1a88cb3923c22253e97b1e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 5 Feb 2026 00:07:22 +0100 Subject: [PATCH 16/16] bugfix for wrongly disabled PINs Skips pin arrays for special bus types where pin array doesn't contain GPIO numbers, but allows all other entries --- wled00/data/settings_um.htm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index a9e6809f..a2d867be 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -58,6 +58,8 @@ // function check(o,k) {} //WLEDMM not needed as we use dropdowns function getPins(o) { if (isO(o)) { + // If this object is a bus instance, extract the "type" field + let busType = o.type !== undefined ? o.type : -1; for (const [k,v] of Object.entries(o)) { if (isO(v)) { owner = k; @@ -65,6 +67,10 @@ continue; } if (k.replace("[]","").substr(-3)=="pin") { + // Skip pin arrays for special bus types where pin array doesn't contain GPIO numbers, but allow all other entries + if (busType >= 80 && busType < 96) continue; // Network buses - pin array stores IP address + if (busType >= 100 && busType <= 110) continue; // HUB75 buses - pin array stores chain length + if (Array.isArray(v)) { for (var i=0; i=0) { pins.push(v[i]); pinO.push(owner); } } else {