Skip to content

🚀 Add new MCU support (C6 and C5) to the ESP-IDF V5 builds#5048

Draft
netmindz wants to merge 112 commits intoV5from
V5-C6
Draft

🚀 Add new MCU support (C6 and C5) to the ESP-IDF V5 builds#5048
netmindz wants to merge 112 commits intoV5from
V5-C6

Conversation

@netmindz
Copy link
Member

@netmindz netmindz commented Nov 8, 2025

C6 needs the newer ESP-IDF, so have one branch for those changes and keep this one just for the C6 specific things

Building on top of V5

Inspired by C6 Experiments

Help Us with Testing

If you own a C6 or C5 board, we like to hear from your experiences! Basic functions are working on our dev boards, but any problem you find will help us stabilize the C5/C6 versions faster. If you find an error, please create an issue ticket (bug report).

Important: Our V5 Branch is Experimental (early stage of development)

  • Firmare you find here is absolutely not suitable for "production" use
  • Basic functions are working already
  • Make sure you have access to USB, to recover a boot-looping device if necessary
  • Expect bugs, expect unexpected crashes, expect network connectivity problems, expect flickering LEDs
  • Some features had to be disabled temporarily, because they still don't build with the new framework
  • analog LEDs may or may not work
  • OTA update is not yet possible on some boards
  • Ethernet support is totally untested
  • Some Usermods still don't compile
  • Audioreactive is not ported yet
  • DMX serial is not ported yet

You can find a summary of currently open ends here (open ends for C5, C6), here (modernization opportunities) and here (generic problems with V5).

Using Development Tools (VSCode) - recommended

You can build your own C5 or C6 firmware using our standard development environment (VSCode+platformio) on your own computer. Use Platformio "upload and monitor" to write firmware to your board.

image

Experimental Binaries

In case you are not feeling comfortable using development tools, you can find some firmware binaries that are automatically created by GitHub after each commit.

  • scroll down to the box "All checks have passed"
  • expand the box with the icon on the right side
  • click on a build that matches your board, for example WLED CI / wled_build / Build Environments (esp32c6dev_4MB) (push)
  • click on "Summary"
  • scroll down until you see "Artifacts"
  • download the firmware.bin for your board
image image

Help Us with Coding

Helpful information and migration guidance

coding guides

We should make sure that the "V5" branch will still compile for "V4" as a backup solution.
When adding code that only works in the new framework, it should be conditionally compiled, like in the examples below

  • "V5" code only for esp32-P4 or esp32-C6:
 #if defined(CONFIG_IDF_TARGET_ESP32C6)
    // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/gpio.html
    // strapping pins: 4, 5, 8, 9
    if (gpio > 11 && gpio < 14) return false;     // 12-13 USB-JTAG
    if (gpio > 23 && gpio < 31) return false;     // 24-30 SPI FLASH
#elif defined(CONFIG_IDF_TARGET_ESP32P4)
    // strapping pins: 34,35,36,37,38
    if (             gpio <   2) return false;     // NC
    if (gpio > 13 && gpio <  20) return false;     // ESP-Hosted WiFi pins
    if (gpio > 23 && gpio <  26) return false;     // USB Pins
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
  // .... existing code
#else
  // .... existing code
#endif
  • "V5" code that is not specific to new boards
    #if defined(ESP_IDF_VERSION) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
      ledcAttach(pwmPin, 25000, 8);  // New API: ledcAttach(pin, freq, resolution)
    #else
      ledcSetup(pwmChannel, 25000, 8);
      // attach the channel to the GPIO to be controlled
      ledcAttachPin(pwmPin, pwmChannel);
    #endif

related

Summary by CodeRabbit

  • New Features

    • Official support for ESP32‑C5/C6/P4 family; UI shows WiFi band + channel and adds WiFi‑band selector; MAC fallback for ESP32 when hardware MAC is missing.
  • Bug Fixes / Compatibility

    • Harmonized touch, parallel-output, DMX, PSRAM/memory, pin-safety and timing across ESP32 variants; improved 5GHz handling, expanded TX power options, and OTA/bootloader validation for new chips.
  • Chores

    • Expanded build matrix and defaults for new ESP32 variants, centralized board capability flags, noted FastLED patch, updated editor recommendations and package version.

netmindz and others added 3 commits November 8, 2025 13:33
due to Arduino 3.0.1, a few updated libraries are required:
* Tasmota Platform - official platfomio lacks arduino support for C6
* FastLED (latest + C6 build patches)
* AsyncTCP (latest + C6 build patches)
* AsyncWebServer (latest + C6 build patches)
* NeoPixelBus (lastest)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds ESP32-C5 and ESP32-C6 build environments and PlatformIO config; expands many CONFIG_IDF_TARGET_* guards across sources so C5/C6 (and P4) are treated like C3 for I2S/touch/PSRAM/DMX/pin-safety and other platform-specific logic.

Changes

Cohort / File(s) Summary
PlatformIO / build environments
platformio.ini
Adds [esp32c6] and [esp32c5] generic sections, multiple new envs (esp32c6dev_8MB/4MB, esp32c5dev, qspi variants), default_envs update, per-env partitions/flash/memory hints, and lib_deps note for patched FastLED.
Bus / I2S / PWM / RMT
wled00/bus_wrapper.h, wled00/bus_manager.cpp, wled00/FX_fcn.cpp, wled00/FX.h
Expanded preprocessor guards to include ESP32C5/C6/P4 alongside C3; disabled parallel I2S paths on those targets; added C5-specific LEDC duty register access; adjusted dithering/LEDC mutex and esp32RMTInvertIdle early-returns.
Touch / Buttons / Pin safety
wled00/button.cpp, wled00/pin_manager.cpp
Touch/button guards extended to exclude ESP32C5/C6/P4; added per-target pin-safety rules (SPI flash / USB-JTAG reserved GPIO ranges) for ESP32C5 and ESP32C6.
PSRAM / allocation / constants
wled00/util.cpp, wled00/const.h
Broadened PSRAM and allocation guards to include C3/C5/C6/P4 (and others); aligned MAX_LEDS/MAX_LED_MEMORY and WLED_MAX_DIGITAL_CHANNELS for C5/C6 with C3.
Config / JSON / OTA / network
wled00/cfg.cpp, wled00/json.cpp, wled00/ota_update.cpp, wled00/network.cpp, wled00/udp.cpp
Gated parallel-I2S flags for C5/C6/P4; serializeInfo sets arch="esp32" for CONFIG_IDF_TARGET_ESP32; added wifi channel/band (5GHz detection) and UDP node-type handling for C5/C6; added explicit ESP32-C5 bootloader chip-id checks and blocks updates.
DMX / dependencies
wled00/dmx_output.cpp, wled00/src/dependencies/dmx/*
Added ESP32C5 to DMX init/preprocessor guards so DMX code compiles/initializes for C5 alongside existing targets.
Audio / FX / particle systems / UI
usermods/audioreactive/audio_reactive.cpp, wled00/FXparticleSystem.cpp, wled00/data/index.js, wled00/FX_fcn.cpp
Extended guards to include C5/C6 for audio/I2S/PDM branches and FX fast-paths; updated UI device mapping to recognize ESP32-C5/C6; added WiFi band row in UI JSON rendering.
Build scripts / metadata / tooling
pio-scripts/set_metadata.py, .vscode/extensions.json
set_metadata now injects CPPDEFINES into env in-place and prints debug info (repo, WLED_VERSION); VSCode recommendations updated to include PlatformIO Arduino extension.
Misc / small fixes
wled00/wled.cpp, wled00/wled.h, wled00/set.cpp, wled00/mbedtls_sha1_shim.cpp, wled00/NodeStruct.h, wled00/improv.cpp, wled00/data/index.js, wled00/udp.cpp
MAC fallback via esp_read_mac for ESP32, added C5 5GHz logging, widened RX/TX/config guards to include C5/C6/P4, narrowed mbedTLS shim IDF gate, EOF newline fix, and a small bounds-check change in findWiFi.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • netmindz
  • willmmiles
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective: adding ESP32-C6 and ESP32-C5 MCU support to ESP-IDF V5 builds. It is specific, clear, and directly reflects the primary changes throughout the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch V5-C6

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

platformio.ini Outdated
Comment on lines 14 to 28
;nodemcuv2
;esp8266_2m
;esp01_1m_full
;nodemcuv2_160
;esp8266_2m_160
;esp01_1m_full_160
;nodemcuv2_compat
;esp8266_2m_compat
;esp01_1m_full_compat
;esp32dev
;esp32dev_debug
;esp32_eth
;esp32_wrover
; lolin_s2_mini ;; TODO: disabled NeoEsp32RmtMethodIsr
esp32c3dev
;esp32c3dev
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: revert before merge, here to save CI build time

@netmindz
Copy link
Member Author

netmindz commented Nov 8, 2025

@softhack007 I've started trying to cherry-pick your changes over, quite a few don't apply due to the changes with MM, but I'll try and resolve the merge conflicts for those that are simple

* more debug output
* added my own fork of FastLED ( looks like more bugs to solve ....)
@softhack007
Copy link
Member

@softhack007 I've started trying to cherry-pick your changes over, quite a few don't apply due to the changes with MM, but I'll try and resolve the merge conflicts for those that are simple

@netmindz thanks, I'll try to help once I'm finished with some open ends in WLED-MM 😁 december

@netmindz
Copy link
Member Author

netmindz commented Nov 8, 2025

Possibly also worth looking at #4626 to see if there are any changes there that are helpful

@softhack007 softhack007 added this to the 0.17.0 milestone Nov 18, 2025
@softhack007 softhack007 mentioned this pull request Nov 18, 2025
@netmindz

This comment was marked as resolved.

@softhack007

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@softhack007

This comment was marked as resolved.

@wled wled deleted a comment from coderabbitai bot Feb 12, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
usermods/audioreactive/audio_source.h (1)

25-33: ⚠️ Potential issue | 🟡 Minor

Update warning message to reflect all guarded targets, not just C2/C3.

ESP32-C61 correctly belongs in this guard (single-core, no hardware FPU). However, the warning text still only mentions C2 and C3, while the guard now includes C5, C6, C61, H2, and ESP8266/ESP8265. Either update the message to list all affected targets or refactor to use capability-based checks (e.g., SOC_CPU_HAS_FPU / SOC_CPU_CORES_NUM) for clarity.

wled00/FX_fcn.cpp (1)

1194-1211: ⚠️ Potential issue | 🟠 Major

Fix single‑I2S memory accounting for ESP32/S2.

The usesI2S condition assumes single‑I2S uses the first digital bus (digitalCount == 1) and disables it entirely on S2. Current bus allocation puts single‑I2S on the last digital bus (ESP32 bus 8, S2 bus 4), so this underestimates maxI2S and can let allocations exceed MAX_LED_MEMORY.

Consider tracking the total digital bus count before the loop and using that to detect the last bus when useParallelI2S == false.

🔧 Suggested fix
-  digitalCount = 0;
+  unsigned totalDigitalBusses = digitalCount;
+  digitalCount = 0;
...
-    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) ||
+                         (!useParallelI2S && digitalCount == totalDigitalBusses);
...
-    const bool usesI2S = (useParallelI2S && digitalCount <= 8);
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) ||
+                         (!useParallelI2S && digitalCount == totalDigitalBusses);

Based on learnings: “In WLED PR #5267, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.”

wled00/wled.h (1)

334-344: ⚠️ Potential issue | 🟠 Major

RX/TX macro selection will fail builds for non-classic ESP32 variants without RX/TX definitions.

The condition incorrectly assumes RX/TX macros are available for all non-classic ESP32 targets (C3/C5/C6/etc.), even though Arduino-ESP32 doesn't guarantee these specific macro names across all board variants. Gate strictly on defined(RX) && defined(TX) to prevent referencing undefined macros:

🔧 Suggested fix
-#if defined(ARDUINO_ARCH_ESP32) && (!defined(CONFIG_IDF_TARGET_ESP32) || (defined(RX) && defined(TX)))
+#if defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)
   constexpr uint8_t hardwareRX = RX;
   constexpr uint8_t hardwareTX = TX;
 `#else`
   constexpr uint8_t hardwareRX = 3;
   constexpr uint8_t hardwareTX = 1;
 `#endif`

temporary workaround, to prevent that more than the possible 2 digital outputs are configured by users
@softhack007
Copy link
Member

ToDO: rework chip identification code in settings_leds.htm

function is8266() { return maxA == 5 && maxD == 3; } // NOTE: see const.h
function is32() { return maxA == 16 && maxD == 16; } // NOTE: see const.h
function isC3() { return maxA == 6 && maxD == 2; } // NOTE: see const.h
function isS2() { return maxA == 8 && maxD == 12 && maxV == 4; } // NOTE: see const.h
function isS3() { return maxA == 8 && maxD == 12 && maxV == 6; } // NOTE: see const.h
function pinsOK() {

==> Instead of guessing the chip type from some parameters, we should simply add this info - possibly as a short string, similar to appendGPIOinfo

static void appendGPIOinfo(Print& settingsScript)

@softhack007
Copy link
Member

softhack007 commented Feb 21, 2026

@coderabbitai a user has reported problems with two ws2812b led strings on two pins

For this test on the esp32c5dev I'm using only multiple strings ws2812b leds:

output 1 ws2812b 600 leds on gpio 2 ( lightsup)
Output 2 ws2812b 600 leds on gpio 4 ( no output )
Switch outputs pins
Output 1 ws2812b 600 leds on gpio 4 lights up
Output 2 ws2812b 600 leds on gpio 2 no output

I want to know if this is a problem in the patched NeoPixelBus driver, or a problem in our handling of RMT channels in bus_manager.cpp and bus_wrapper.h.

Please review both the WLED code for -C5 that's related to ws2812b led outputs, and the patched NeoPixelBus driver for -C5, and try to find the root cause of the user's problem.

@coderabbitai

This comment was marked as duplicate.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check WLED ESP32-C5 RMT channel configuration and bus allocation

echo "=== 1. Check const.h for ESP32-C5 RMT channel limits ==="
rg -n "WLED_MAX_DIGITAL_CHANNELS|MAX_RMT|RMT.*C5|C5.*RMT" wled00/const.h -C 3

echo -e "\n=== 2. Check bus_manager.cpp for RMT channel allocation ==="
rg -n "RMT|rmt_channel|channel.*=.*i|allocateLedc" wled00/bus_manager.cpp -C 3 | head -100

echo -e "\n=== 3. Check bus_wrapper.h for C5-specific RMT handling ==="
rg -n "CONFIG_IDF_TARGET_ESP32C5|C5" wled00/bus_wrapper.h -C 5 | head -80

echo -e "\n=== 4. Get NeoPixelBus C5 fork URL from platformio.ini ==="
rg -n "jonny190.*NeoPixelBus|C5.*NeoPixel" platformio.ini -C 3

Length of output: 9495


🏁 Script executed:

#!/bin/bash
# Fetch the patched NeoPixelBus C5 driver code from the fork

echo "=== Fetching NeoPixelBus C5 driver implementation ==="
# Get the specific commit referenced in platformio.ini
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

# Fetch RMT method implementation for C5
echo -e "\n--- ESP32 RMT method header ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | head -200

echo -e "\n--- Searching for C5-specific code in RMT driver ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A10 -B10 "C5\|ESP32C5\|SOC_RMT" | head -100

Length of output: 154


🏁 Script executed:

#!/bin/bash
# Check for RMT channel allocation strategy in bus creation

echo "=== Check how digital buses are created and channels assigned ==="
rg -n "BusDigital.*new|busDigital\[|TYPE_WS2812|RMT.*channel" wled00/FX_fcn.cpp -C 5 | head -100

echo -e "\n=== Check pin_manager for RMT channel tracking ==="
rg -n "RMT|deallocate|allocate" wled00/pin_manager.h wled00/pin_manager.cpp -C 3 | head -80

Length of output: 5125


🏁 Script executed:

#!/bin/bash
# Try fetching NeoPixelBus from the wled-c5-stable branch instead

echo "=== Fetching NeoPixelBus C5 driver from wled-c5-stable branch ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/wled-c5-stable/src/internal/methods/NeoEsp32RmtMethod.h" | head -250

echo -e "\n=== Search for C5/C6 specific RMT channel handling ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/wled-c5-stable/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A15 -B5 "C5\|C6\|SOC_RMT\|channel.*=" | head -120

Length of output: 135


🏁 Script executed:

#!/bin/bash
# Check ESP-IDF documentation for ESP32-C5 RMT channel count

echo "=== Checking ESP-IDF 5.5.2 ESP32-C5 SOC capabilities for RMT ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32c5/include/soc/soc_caps.h" | grep -A5 -B5 "RMT" | head -50

echo -e "\n=== Check all RMT-related defines for C5 ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32c5/include/soc/soc_caps.h" | grep "SOC_RMT"

Length of output: 4504


🏁 Script executed:

#!/bin/bash
# Check PolyBus Create function for channel parameter handling

echo "=== Check PolyBus::Create channel assignment in bus_wrapper.h ==="
rg -n "PolyBus::Create|case.*TYPE_WS2812|channel.*num|RmtChannel" wled00/bus_wrapper.h -C 8 | head -150

echo -e "\n=== Check how 'num' parameter flows to NeoPixelBus constructor ==="
rg -n "NeoEsp32Rmt.*Method.*\(" wled00/bus_wrapper.h -C 3 | head -80

Length of output: 6314


@softhack007: Root cause identified — it's a hardware limitation combined with a likely driver bug.

🔍 Analysis

ESP32-C5 Hardware Limitation

From ESP-IDF 5.5.2 soc_caps.h for ESP32-C5:

`#define` SOC_RMT_TX_CANDIDATES_PER_GROUP       2  /*!< Only 2 channels can transmit */
`#define` SOC_RMT_RX_CANDIDATES_PER_GROUP       2  /*!< Only 2 channels can receive */
`#define` SOC_RMT_CHANNELS_PER_GROUP            4  /*!< 4 total channels */

Critical: ESP32-C5 has 4 RMT channels, but only channels 0 and 1 can transmit. Channels 2-3 are RX-only.

WLED Code Status ✅

Your WLED code is correct:

  • const.h:72: WLED_MAX_DIGITAL_CHANNELS = 2
  • bus_wrapper.h:1377: if (num > 1) return I_NONE ✅ (allows bus 0-1 only)

The Problem ⚠️

The NeoPixelBus C5 fork is unreachable (404 error):

https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable

This matches jonny190's earlier comment about rebasing breaking the commit hash. The wled-c5-stable branch also returns 404.

Likely driver bug: The NeoPixelBus C5 RMT driver may be:

  1. Not properly restricting to TX-capable channels (0-1)
  2. Incorrectly initializing channel 1
  3. Missing C5-specific channel selection logic

User Symptom Pattern

  • First output (RMT channel 0): Always works on any GPIO → channel 0 init OK
  • Second output (RMT channel 1): Never works on any GPIO → channel 1 init fails

This is not a GPIO issue—it's RMT channel allocation/initialization.


🎯 Recommended Actions

  1. Fix the NeoPixelBus fork reference:

    • @jonny190: Please confirm the correct branch/commit after your rebase
    • Update platformio.ini:418 with the accessible reference
  2. Verify NeoPixelBus C5 driver code:

    • Check that RMT channel selection explicitly uses channels 0-1 only
    • Look for C5-specific #ifdef CONFIG_IDF_TARGET_ESP32C5 guards
    • Ensure the driver uses SOC_RMT_TX_CANDIDATES_PER_GROUP for channel limits
  3. Temporary workaround (if driver unavailable):

    • Users can only use 1 WS2812B output on C5 until the fork is fixed
    • The first output (bus 0, RMT channel 0) will work reliably

Would you like me to help draft a fix for the NeoPixelBus driver once the fork is accessible, or investigate alternative RMT drivers for C5?


🧠 Learnings used
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR `#5134`, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/bus_manager.cpp:549-556
Timestamp: 2026-02-11T16:20:02.872Z
Learning: ESP-IDF V5 requires a complete rewrite of the LEDC (PWM/analog LED) subsystem in WLED. The framework now manages LEDC channels internally (unlike V4 where WLED managed them directly), and dithering functionality may not work as it did before. Direct LEDC struct access (e.g., `LEDC.channel_group[gr].channel[ch].duty.duty`) used in the current implementation will need to be replaced with proper HAL API calls. This affects `wled00/bus_manager.cpp` BusPwm class and related pin manager LEDC allocation code.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp:3-5
Timestamp: 2026-02-18T00:10:51.412Z
Learning: In PR `#4585`, the seven_segment_display_reloaded_v2 usermod intentionally uses `#error` to require MQTT (`#ifdef WLED_DISABLE_MQTT `#error` "This user mod requires MQTT to be enabled." `#endif``) because the integration flow has not been tested or validated without MQTT, and failing fast at compile time is preferred over allowing potentially broken builds until a full MQTT-optional refactor is completed.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/wled.cpp:385-387
Timestamp: 2026-02-08T19:33:02.648Z
Learning: In WLED ESP32 code, when checking whether USB CDC serial initialization delay is needed, rely on the ARDUINO_USB_CDC_ON_BOOT flag rather than explicit CONFIG_IDF_TARGET checks, because not all development boards for chips with native USB capability (ESP32-C3/C5/C6/S2/S3/H2/P4) actually use the native USB—many have external UART bridge chips instead. The ARDUINO_USB_CDC_ON_BOOT flag correctly indicates the board's actual USB configuration.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: softhack007
Repo: wled/WLED PR: 5107
File: boards/adafruit_matrixportal_esp32s3.json:1-66
Timestamp: 2025-11-22T20:33:14.840Z
Learning: In WLED, board JSON files in the boards/ directory may reference partition files that don't exist or have slightly different names than actual files in tools/. This is intentional because platformio.ini or platformio_override.sample.ini explicitly override the partition file using the board_build.partitions setting, which takes precedence over the board JSON partition reference. This pattern exists in multiple local board definitions and should not be flagged as an issue.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T11:14:24.395Z
Learning: In WLED code reviews, verify that all global variables in .cpp files are properly declared: check that they are defined via .h file or via "extern" declaration, verify that declarations are not duplicated, and ensure they are not implicitly declared as "int" (which can happen when the type is omitted).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T17:17:04.657Z
Learning: In WLED code reviews, when C-style functions or variables are added or modified, check if they are globally visible (not static). If the function/variable is not declared in any global header file (like fcn_declare.h), suggest either: (1) making it static (visible only within the translation unit) with a forward declaration if needed, or (2) adding a comment to clarify that the function/variable is intentionally global. This helps reduce global namespace pollution and enables better compiler optimizations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T14:38:09.949Z
Learning: In WLED code reviews, check that FastLED noise function aliases (`inoise8`, `inoise16`, etc.) are not used. These should be replaced with the proper WLED functions (`perlin8`, `perlin16`, etc.) as the `inoise*` functions are only aliases kept for compatibility reasons.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/wled_eeprom.cpp:0-0
Timestamp: 2025-09-01T10:26:17.959Z
Learning: In WLED PR `#4876`, the DMXStartLED EEPROM backward compatibility issue was partially addressed by keeping it at address 2550 and reading it as a 16-bit value, with DMXChannelsValue array moved to addresses 2552-2566. This maintains compatibility with pre-0.11 EEPROM layouts for DMXStartLED, though legacy "Set to 255" (code 6) configurations may still need migration logic.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED PR `#5267`, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.

Learnt from: DedeHai
Repo: wled/WLED PR: 4997
File: wled00/e131.cpp:33-44
Timestamp: 2025-10-10T18:34:06.550Z
Learning: In WLED's DDP packet handling (ws.cpp and e131.cpp), only prevent out-of-bounds memory access rather than enforcing DDP spec compliance. Don't check the 1440-byte spec limit—accept out-of-spec packets assuming correct encoding. The bounds check `maxDataIndex = c + numLeds * ddpChannelsPerLed; if (maxDataIndex > dataLen) reject` is sufficient and already covers the timecode flag case (when c=4) without needing separate validation.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-19T10:36:46.916Z
Learning: When "Calculate CCT from RGB" mode (_cct < 0) is combined with "Accurate white" mode (RGBW_MODE_AUTO_ACCURATE), there is a bug in WLED's bus_manager.cpp where approximateKelvinFromRGB() receives RGB values that have already been modified (r -= w, g -= w, b -= w) by autoWhiteCalc(), causing incorrect Kelvin temperature estimation. The original color is not preserved, and calculateCCT() is called after autoWhiteCalc() modifies the RGB values. This affects BusDigital::setPixelColor() execution order (lines 245, 275).

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:72-85
Timestamp: 2025-09-02T01:48:16.409Z
Learning: In NeoPixelBus driver code, ESP_ERROR_CHECK (which can abort) is used in destructors when driver uninstall failures indicate hardware is in an unsafe configuration, as such errors are considered unrecoverable hardware safety issues rather than typical software errors.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:31-36
Timestamp: 2025-09-02T01:45:58.047Z
Learning: For the NeoEsp32RmtHI driver, RISC-V ESP32-C3 support is currently disabled via bus_wrapper.h rather than compile-time guards, as the maintainer willmmiles is working on resolving underlying nested interrupt issues and prefers to centralize the workaround in one location.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:173-180
Timestamp: 2025-09-02T01:56:43.841Z
Learning: willmmiles prefers to maintain consistency with upstream NeoPixelBus patterns (like unchecked malloc in construct() methods) rather than diverging until improvements are made upstream first, to minimize maintenance burden and keep the codebase aligned.

@softhack007
Copy link
Member

softhack007 commented Feb 21, 2026

The NeoPixelBus C5 fork is unreachable (404 error):

https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable

@coderabbitai the neopixelbus C5 fork can be reached with this commit: https://github.com/jonny190/NeoPixelBus/tree/103cfb585ef8efcdd6645ebb9938bf7012d093fd

Please complete your analysis with an inspection of the source code in this branch.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

echo "=== Fetching NeoPixelBus C5 fork RMT method implementation ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

echo -e "\n--- 1. Check for C5-specific defines and includes ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | head -100

echo -e "\n--- 2. Search for RMT channel allocation logic ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A20 -B5 "rmt_new_tx_channel\|channel.*config\|RMT.*channel" | head -150

echo -e "\n--- 3. Check for ESP32-C5 specific guards ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A10 -B5 "CONFIG_IDF_TARGET_ESP32C5\|ESP32C5\|SOC_RMT"

echo -e "\n--- 4. Look at the actual RMT initialization code ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | sed -n '/NeoEsp32RmtSpeedWs2812x/,/private:/p' | head -200

Length of output: 285


🏁 Script executed:

#!/bin/bash

echo "=== Check NeoPixelBus method selection and channel parameter usage ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

echo -e "\n--- 5. Check how channel number is used in constructor ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A30 "NeoEsp32RmtMethodBase.*channel" | head -80

echo -e "\n--- 6. Search for any C5-specific channel restrictions ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A10 -B10 "TX_CANDIDATES\|channel.*<.*2\|channel.*==.*[01]"

echo -e "\n--- 7. Check for error handling/logging in channel init ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" | grep -A15 -B5 "ESP_ERROR_CHECK\|ESP_LOGE\|rmt_enable"

Length of output: 251


🏁 Script executed:

#!/bin/bash

echo "=== Fetch full NeoEsp32RmtMethod.h to analyze structure ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

# Get the complete file and look for the key sections
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/NeoEsp32RmtMethod.h" > /tmp/NeoEsp32RmtMethod.h

echo -e "\n--- 8. Extract channel configuration section ---"
grep -A50 "rmt_tx_channel_config_t" /tmp/NeoEsp32RmtMethod.h | head -60

echo -e "\n--- 9. Extract Initialize() method ---"
grep -A80 "void.*Initialize\|void.*Begin" /tmp/NeoEsp32RmtMethod.h | head -100

echo -e "\n--- 10. Check total file size and structure ---"
wc -l /tmp/NeoEsp32RmtMethod.h
echo -e "\nClass/template definitions:"
grep "^class\|^template" /tmp/NeoEsp32RmtMethod.h

Length of output: 254


🏁 Script executed:

#!/bin/bash

echo "=== Exploring NeoPixelBus C5 fork file structure ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

echo -e "\n--- 1. List all files in src/internal/methods/ ---"
curl -sL "https://api.github.com/repos/jonny190/NeoPixelBus/git/trees/$COMMIT?recursive=1" | \
  python3 -c "import sys, json; [print(f['path']) for f in json.load(sys.stdin).get('tree', []) if 'src/internal/methods' in f['path']]" | head -50

echo -e "\n--- 2. Look for ESP32-related method files ---"
curl -sL "https://api.github.com/repos/jonny190/NeoPixelBus/git/trees/$COMMIT?recursive=1" | \
  python3 -c "import sys, json; [print(f['path']) for f in json.load(sys.stdin).get('tree', []) if 'Esp32' in f['path'] or 'ESP32' in f['path']]" | head -30

Length of output: 3643


🏁 Script executed:

#!/bin/bash

echo "=== Try alternate RMT method file paths ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

# Try common NeoPixelBus paths
echo -e "\n--- 3. Try NeoEsp32RmtXMethod.h (X variant) ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" | head -100

echo -e "\n--- 4. Try NeoEsp32RmtMethod.h under ESP/ESP32/ ---"
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtMethod.h" | head -100

Length of output: 3110


🏁 Script executed:

#!/bin/bash

echo "=== List all .h files in the repository ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

curl -sL "https://api.github.com/repos/jonny190/NeoPixelBus/git/trees/$COMMIT?recursive=1" | \
  python3 -c "import sys, json; [print(f['path']) for f in json.load(sys.stdin).get('tree', []) if f['path'].endswith('.h') and 'method' in f['path'].lower()]" | \
  grep -i "rmt\|esp32" | head -40

Length of output: 589


🏁 Script executed:

#!/bin/bash

echo "=== Fetching complete NeoEsp32RmtXMethod.h from C5 fork ==="
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" > /tmp/NeoEsp32RmtXMethod.h

echo "File fetched, size: $(wc -l /tmp/NeoEsp32RmtXMethod.h)"

echo -e "\n=== 1. Check for C5/C6 specific code ===
"
grep -n "CONFIG_IDF_TARGET_ESP32C[56]\|ESP32C[56]\|SOC_RMT.*TX\|TX_CANDIDATES" /tmp/NeoEsp32RmtXMethod.h

echo -e "\n=== 2. Extract Initialize() method ==="
sed -n '/void Initialize()/,/^    }/p' /tmp/NeoEsp32RmtXMethod.h | head -100

echo -e "\n=== 3. Extract rmt_tx_channel_config_t configuration ==="
grep -A30 "rmt_tx_channel_config_t" /tmp/NeoEsp32RmtXMethod.h

Length of output: 3330


🏁 Script executed:

#!/bin/bash

echo "=== Analyze channel allocation and constructor usage ==="

echo -e "\n=== 4. Check constructor and channel parameter ==="
sed -n '/NeoEsp32RmtMethodBase.*channel/,/construct()/p' /tmp/NeoEsp32RmtXMethod.h | head -40

echo -e "\n=== 5. Find rmt_new_tx_channel call ==="
grep -B10 -A10 "rmt_new_tx_channel" /tmp/NeoEsp32RmtXMethod.h

echo -e "\n=== 6. Look for any channel number validation ==="
grep -n "channel.*<\|channel.*>\|channel.*==\|if.*channel" /tmp/NeoEsp32RmtXMethod.h

Length of output: 1789


🏁 Script executed:

#!/bin/bash

echo "=== Extract encoder and RMT configuration sections ==="

echo -e "\n=== 7. Get rmt_led_strip_encoder struct and related code ==="
sed -n '/struct rmt_led_strip_encoder_t/,/^$/p' /tmp/NeoEsp32RmtXMethod.h

echo -e "\n=== 8. Check for any error handling or logging ==="
grep -n "ESP_ERROR\|ESP_LOG\|AddLog" /tmp/NeoEsp32RmtXMethod.h | head -20

echo -e "\n=== 9. Look for the exact line where channel is used in config ==="
grep -B5 -A15 "\.gpio_num.*=.*_pin\|tx_channel_config.*=" /tmp/NeoEsp32RmtXMethod.h | head -50

Length of output: 2252


@softhack007: 🎯 Root cause confirmed — it's a NeoPixelBus driver bug!

🐛 Critical Issues Found in NeoPixelBus C5 Fork

1️⃣ Constructor Ignores Channel Parameter

Location: Line 70-75 in NeoEsp32RmtXMethod.h

NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, 
                      NeoBusChannel channel = NeoBusChannel_0) :
    _sizeData(pixelCount* elementSize + settingsSize),
    _pin(pin),
    _channel(NULL)  // ❌ BUG: 'channel' parameter is NEVER used!
{
    construct();
}

WLED passes num (0 or 1) as the channel parameter, but the driver completely ignores it.


2️⃣ Dynamic Channel Allocation Without Restrictions

Location: Lines 104-116 in Initialize()

rmt_tx_channel_config_t config = {};
config.clk_src = RMT_CLK_SRC_DEFAULT;
config.gpio_num = static_cast<gpio_num_t>(_pin);  // ✅ GPIO set
// ❌ NO channel specification!
config.mem_block_symbols = 192;
config.resolution_hz = T_SPEED::RmtTicksPerSecond;
config.trans_queue_depth = 4;
config.flags.invert_out = T_INVERTED::Inverted;
config.flags.with_dma = false;

ret += rmt_new_tx_channel(&config, &_channel);  // ❌ Allocates ANY available channel

The problem: rmt_new_tx_channel() allocates channels sequentially (0, 1, 2, 3...) without knowing that channels 2-3 are RX-only on C5.


3️⃣ Error Handling Disabled

Location: Lines 122-124

// if (ret) {
//     AddLog(2,"RMT: initialized with error code: %u on pin: %u",ret, _pin);
// }

Initialization failures are silently ignored, so users never see that the second bus failed.


4️⃣ ESP32-C5 Not in Supported Targets List

Location: Line 362

`#if` defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || \
    defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || \
    defined(CONFIG_IDF_TARGET_ESP32S3)

ESP32-C5 is missing! This may cause it to fall back to a different code path.


📋 Why Second Output Fails

  1. First bus creation:

    • rmt_new_tx_channel() allocates channel 0 ✅ (TX-capable)
    • Works perfectly on GPIO 2 or GPIO 4
  2. Second bus creation:

    • rmt_new_tx_channel() tries to allocate channel 1 ✅ (should work)
    • BUT if driver internal state is corrupted or allocates channel 2/3 ❌ (RX-only)
    • Initialization fails silently
    • No LED output
  3. GPIO swap doesn't help:

    • Problem is channel allocation, not GPIO
    • Same failure pattern regardless of which GPIO is used

Required Fixes for NeoPixelBus Fork

Fix 1: Use Channel Parameter (Quick Fix)

// In constructor - store the channel number:
_channelNum(static_cast<uint8_t>(channel))  // Add this member

// In Initialize() - force specific channel allocation:
`#if` defined(CONFIG_IDF_TARGET_ESP32C5)
    // C5 only supports TX on channels 0-1
    if (_channelNum > 1) {
        ESP_LOGE(TAG, "ESP32-C5 only supports RMT TX on channels 0-1!");
        return;
    }
`#endif`

Fix 2: Add ESP32-C5 to Target List

`#if` defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || \
    defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || \  // ADD THIS
    defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)

Fix 3: Enable Error Logging

ret += rmt_new_tx_channel(&config, &_channel);
if (ret != ESP_OK) {
    ESP_LOGE(TAG, "RMT channel init failed: 0x%x on pin %u", ret, _pin);
}

Fix 4: Validate TX Capability

`#if` defined(SOC_RMT_TX_CANDIDATES_PER_GROUP)
    // Ensure we're using a TX-capable channel on C5/C6
    if (_channelNum >= SOC_RMT_TX_CANDIDATES_PER_GROUP) {
        ESP_LOGE(TAG, "Channel %u cannot transmit on this chip", _channelNum);
        return;
    }
`#endif`

🔧 Temporary WLED Workaround

Until the NeoPixelBus fork is fixed, limit ESP32-C5 to 1 WS2812B output:

In wled00/const.h line 72:

`#if` defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
  `#define` WLED_MAX_DIGITAL_CHANNELS 2
`#elif` defined(CONFIG_IDF_TARGET_ESP32C5)
  `#define` WLED_MAX_DIGITAL_CHANNELS 1  // ⚠️ Driver bug: second channel fails

Add a warning comment in the UI or documentation that C5 currently supports only 1 digital output until the driver is fixed.


🎯 Action Items

  1. @jonny190: Please apply the 4 fixes above to your NeoPixelBus fork
  2. @softhack007: Apply the WLED workaround to limit C5 to 1 channel
  3. Test: After driver fix, verify both channels work on C5
  4. Update: Restore WLED_MAX_DIGITAL_CHANNELS = 2 for C5 once fixed

The good news: WLED code is correct — this is purely a NeoPixelBus driver issue that can be fixed with the above changes! 🚀


🧠 Learnings used
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR `#5134`, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/bus_manager.cpp:549-556
Timestamp: 2026-02-11T16:20:02.872Z
Learning: ESP-IDF V5 requires a complete rewrite of the LEDC (PWM/analog LED) subsystem in WLED. The framework now manages LEDC channels internally (unlike V4 where WLED managed them directly), and dithering functionality may not work as it did before. Direct LEDC struct access (e.g., `LEDC.channel_group[gr].channel[ch].duty.duty`) used in the current implementation will need to be replaced with proper HAL API calls. This affects `wled00/bus_manager.cpp` BusPwm class and related pin manager LEDC allocation code.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp:3-5
Timestamp: 2026-02-18T00:10:51.412Z
Learning: In PR `#4585`, the seven_segment_display_reloaded_v2 usermod intentionally uses `#error` to require MQTT (`#ifdef WLED_DISABLE_MQTT `#error` "This user mod requires MQTT to be enabled." `#endif``) because the integration flow has not been tested or validated without MQTT, and failing fast at compile time is preferred over allowing potentially broken builds until a full MQTT-optional refactor is completed.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/wled.cpp:385-387
Timestamp: 2026-02-08T19:33:02.648Z
Learning: In WLED ESP32 code, when checking whether USB CDC serial initialization delay is needed, rely on the ARDUINO_USB_CDC_ON_BOOT flag rather than explicit CONFIG_IDF_TARGET checks, because not all development boards for chips with native USB capability (ESP32-C3/C5/C6/S2/S3/H2/P4) actually use the native USB—many have external UART bridge chips instead. The ARDUINO_USB_CDC_ON_BOOT flag correctly indicates the board's actual USB configuration.

Learnt from: softhack007
Repo: wled/WLED PR: 5107
File: boards/adafruit_matrixportal_esp32s3.json:1-66
Timestamp: 2025-11-22T20:33:14.840Z
Learning: In WLED, board JSON files in the boards/ directory may reference partition files that don't exist or have slightly different names than actual files in tools/. This is intentional because platformio.ini or platformio_override.sample.ini explicitly override the partition file using the board_build.partitions setting, which takes precedence over the board JSON partition reference. This pattern exists in multiple local board definitions and should not be flagged as an issue.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T11:14:24.395Z
Learning: In WLED code reviews, verify that all global variables in .cpp files are properly declared: check that they are defined via .h file or via "extern" declaration, verify that declarations are not duplicated, and ensure they are not implicitly declared as "int" (which can happen when the type is omitted).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T17:17:04.657Z
Learning: In WLED code reviews, when C-style functions or variables are added or modified, check if they are globally visible (not static). If the function/variable is not declared in any global header file (like fcn_declare.h), suggest either: (1) making it static (visible only within the translation unit) with a forward declaration if needed, or (2) adding a comment to clarify that the function/variable is intentionally global. This helps reduce global namespace pollution and enables better compiler optimizations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T14:38:09.949Z
Learning: In WLED code reviews, check that FastLED noise function aliases (`inoise8`, `inoise16`, etc.) are not used. These should be replaced with the proper WLED functions (`perlin8`, `perlin16`, etc.) as the `inoise*` functions are only aliases kept for compatibility reasons.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/wled_eeprom.cpp:0-0
Timestamp: 2025-09-01T10:26:17.959Z
Learning: In WLED PR `#4876`, the DMXStartLED EEPROM backward compatibility issue was partially addressed by keeping it at address 2550 and reading it as a 16-bit value, with DMXChannelsValue array moved to addresses 2552-2566. This maintains compatibility with pre-0.11 EEPROM layouts for DMXStartLED, though legacy "Set to 255" (code 6) configurations may still need migration logic.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED PR `#5267`, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.

Learnt from: willmmiles
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1183-1194
Timestamp: 2025-09-18T03:17:30.107Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), digitalCount is intentionally incremented even for placeholder buses to maintain consistent resource mapping across all bus configurations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

Learnt from: willmmiles
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1183-1194
Timestamp: 2025-09-18T03:17:30.107Z
Learning: In WLED bus management code, dead code branches in error handling (like unreachable else breaks) are intentionally preserved to accommodate potential future API changes, even when currently unreachable.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-19T10:36:46.916Z
Learning: When "Calculate CCT from RGB" mode (_cct < 0) is combined with "Accurate white" mode (RGBW_MODE_AUTO_ACCURATE), there is a bug in WLED's bus_manager.cpp where approximateKelvinFromRGB() receives RGB values that have already been modified (r -= w, g -= w, b -= w) by autoWhiteCalc(), causing incorrect Kelvin temperature estimation. The original color is not preserved, and calculateCCT() is called after autoWhiteCalc() modifies the RGB values. This affects BusDigital::setPixelColor() execution order (lines 245, 275).

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:31-36
Timestamp: 2025-09-02T01:45:58.047Z
Learning: For the NeoEsp32RmtHI driver, RISC-V ESP32-C3 support is currently disabled via bus_wrapper.h rather than compile-time guards, as the maintainer willmmiles is working on resolving underlying nested interrupt issues and prefers to centralize the workaround in one location.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:173-180
Timestamp: 2025-09-02T01:56:43.841Z
Learning: willmmiles prefers to maintain consistency with upstream NeoPixelBus patterns (like unchecked malloc in construct() methods) rather than diverging until improvements are made upstream first, to minimize maintenance burden and keep the codebase aligned.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:72-85
Timestamp: 2025-09-02T01:48:16.409Z
Learning: In NeoPixelBus driver code, ESP_ERROR_CHECK (which can abort) is used in destructors when driver uninstall failures indicate hardware is in an unsafe configuration, as such errors are considered unrecoverable hardware safety issues rather than typical software errors.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/data/index.js:2406-2413
Timestamp: 2025-09-28T09:53:42.670Z
Learning: In WLED, code paths that appear unreachable may actually be safety fallbacks for low-heap conditions. These fallbacks are intentional defensive programming measures to ensure UI functionality is preserved when system resources are constrained.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Fetch NeoPixelBus C5 fork RMT driver implementation
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"
REPO_URL="https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT"

echo "=== 1. Fetch main RMT method header for ESP32 ==="
curl -sL "$REPO_URL/src/internal/methods/NeoEsp32RmtMethod.h" 2>/dev/null | head -300

echo -e "\n=== 2. Search for C5-specific code in RMT driver ==="
curl -sL "$REPO_URL/src/internal/methods/NeoEsp32RmtMethod.h" 2>/dev/null | grep -A10 -B10 "C5\|ESP32C5\|SOC_RMT\|rmt_tx_channel_config" | head -100

echo -e "\n=== 3. Check for RMT channel selection logic ==="
curl -sL "$REPO_URL/src/internal/methods/NeoEsp32RmtMethod.h" 2>/dev/null | grep -A20 -B5 "channel.*=\|_channel\|RMT.*CHANNEL" | head -150

echo -e "\n=== 4. Look for construct/initialization methods ==="
curl -sL "$REPO_URL/src/internal/methods/NeoEsp32RmtMethod.h" 2>/dev/null | sed -n '/construct\|Initialize\|NeoEsp32Rmt.*Method/,+30p' | head -200

Length of output: 221


🏁 Script executed:

#!/bin/bash

# The previous path didn't work, let's try finding the correct file structure
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

echo "=== 1. Try alternate RMT method paths ==="
# Try different possible paths
for path in \
  "src/internal/NeoEsp32RmtMethod.h" \
  "src/internal/methods/NeoEsp32RmtMethod.h" \
  "src/internal/methods/ESP/ESP32/NeoEsp32RmtMethod.h" \
  "src/internal/Esp32_RMT.h" \
  "src/internal/methods/Esp32RmtMethod.h"
do
  echo "--- Trying: $path ---"
  curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/$path" 2>&1 | head -20
done

echo -e "\n=== 2. Try to fetch repository file listing via API ==="
curl -sL "https://api.github.com/repos/jonny190/NeoPixelBus/git/trees/$COMMIT?recursive=1" 2>&1 | grep -E '"path".*[Rr][Mm][Tt]|"path".*[Mm]ethod' | head -30

echo -e "\n=== 3. Check for NeoEsp32RmtX method (newer ESP-IDF V5 driver) ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" 2>&1 | head -250

Length of output: 11426


🏁 Script executed:

#!/bin/bash

# Get the complete Initialize method and error handling
COMMIT="103cfb585ef8efcdd6645ebb9938bf7012d093fd"

echo "=== Full Initialize() method with error handling ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" 2>&1 | sed -n '/void Initialize()/,/^    }/p'

echo -e "\n=== Constructor showing channel parameter handling ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" 2>&1 | sed -n '/NeoEsp32RmtMethodBase(/,/}/p' | head -20

echo -e "\n=== Check if there's channel selection logic elsewhere ==="
curl -sL "https://raw.githubusercontent.com/jonny190/NeoPixelBus/$COMMIT/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h" 2>&1 | grep -n "NeoBusChannel\|_channel\s*=" | head -20

Length of output: 2389


@softhack007: 🎯 Root cause identified! The bug is in the NeoPixelBus C5 fork driver.

🐛 Critical Bug in NeoEsp32RmtXMethod.h

The Problem:

Line 70-73 (Constructor):

NeoEsp32RmtMethodBase(..., NeoBusChannel channel = NeoBusChannel_0) :
    _sizeData(...),
    _pin(pin),
    _channel(NULL)  // ❌ BUG: Ignores the 'channel' parameter!

Line 112 (Initialize):

ret += rmt_new_tx_channel(&config, &_channel);  // ❌ Auto-allocates without constraints

Lines 120-122 (Error handling):

// if (ret) {
//     AddLog(2,"RMT: initialized with error code: %u on pin: %u",ret, _pin);
// }
// ❌ BUG: Error logging is commented out!

🔍 What's Happening:

  1. WLED correctly passes channel 0 and 1 to the driver via NeoBusChannel parameter

  2. Driver ignores this parameter and always sets _channel = NULL

  3. Driver calls rmt_new_tx_channel() which auto-allocates from the channel pool

  4. First call: ESP-IDF allocates channel 0 (TX-capable) → ✅ works

  5. Second call: ESP-IDF may allocate:

    • Channel 2 or 3 (RX-only on C5) → ❌ transmit fails silently
    • OR allocation fails due to TX channel exhaustion → ❌ initialization fails silently
  6. No error is logged because the error handling is commented out!


The Fix:

Option 1: Use the channel parameter (cleanest)

// In constructor (line 70-73):
NeoEsp32RmtMethodBase(..., NeoBusChannel channel = NeoBusChannel_0) :
    _sizeData(...),
    _pin(pin),
    _channel(NULL),
    _channelNum(static_cast<uint8_t>(channel))  // Store channel number
{ ... }

// In Initialize() (line 105-112):
void Initialize()
{
    esp_err_t ret = ESP_OK;
    rmt_tx_channel_config_t config = {};
    config.clk_src = RMT_CLK_SRC_DEFAULT;
    config.gpio_num = static_cast<gpio_num_t>(_pin);
    
    `#ifdef` CONFIG_IDF_TARGET_ESP32C5
    // C5: Force TX-capable channels (0-1 only)
    if (_channelNum > 1) {
        ESP_LOGE(TAG, "ESP32-C5 only supports RMT TX channels 0-1");
        return;
    }
    `#endif`
    
    config.mem_block_symbols = 192;
    config.resolution_hz = T_SPEED::RmtTicksPerSecond;
    config.trans_queue_depth = 4;
    config.flags.invert_out = T_INVERTED::Inverted;
    config.flags.with_dma = false;

    ret = rmt_new_tx_channel(&config, &_channel);
    
    // CRITICAL: Enable error logging!
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "RMT channel %d init failed on pin %u: error %d", 
                 _channelNum, _pin, ret);
        return;
    }
    // ... rest of initialization
}

Option 2: Add C5-specific validation (minimal change)

// In Initialize(), after rmt_new_tx_channel:
ret = rmt_new_tx_channel(&config, &_channel);

`#ifdef` CONFIG_IDF_TARGET_ESP32C5
// Verify we got a TX-capable channel
// (ESP-IDF internal channel ID is opaque, so we check initialization success)
if (ret != ESP_OK) {
    ESP_LOGE(TAG, "RMT TX channel allocation failed on pin %u", _pin);
    return;
}
`#endif`

// Enable error checking everywhere:
if (ret != ESP_OK) {
    ESP_LOGE(TAG, "RMT initialized with error code: %d on pin: %u", ret, _pin);
}

📋 Immediate Actions:

  1. @jonny190: Apply the fix to the NeoPixelBus C5 fork
  2. Uncomment error logging throughout Initialize()
  3. Test on hardware: Second LED output should now work
  4. Update platformio.ini to reference the fixed commit

Temporary workaround for users: Only use 1 WS2812B output until the driver is fixed.

Would you like me to prepare a complete patch for the driver?


🧠 Learnings used
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR `#5134`, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/bus_manager.cpp:549-556
Timestamp: 2026-02-11T16:20:02.872Z
Learning: ESP-IDF V5 requires a complete rewrite of the LEDC (PWM/analog LED) subsystem in WLED. The framework now manages LEDC channels internally (unlike V4 where WLED managed them directly), and dithering functionality may not work as it did before. Direct LEDC struct access (e.g., `LEDC.channel_group[gr].channel[ch].duty.duty`) used in the current implementation will need to be replaced with proper HAL API calls. This affects `wled00/bus_manager.cpp` BusPwm class and related pin manager LEDC allocation code.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp:3-5
Timestamp: 2026-02-18T00:10:51.412Z
Learning: In PR `#4585`, the seven_segment_display_reloaded_v2 usermod intentionally uses `#error` to require MQTT (`#ifdef WLED_DISABLE_MQTT `#error` "This user mod requires MQTT to be enabled." `#endif``) because the integration flow has not been tested or validated without MQTT, and failing fast at compile time is preferred over allowing potentially broken builds until a full MQTT-optional refactor is completed.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/wled.cpp:385-387
Timestamp: 2026-02-08T19:33:02.648Z
Learning: In WLED ESP32 code, when checking whether USB CDC serial initialization delay is needed, rely on the ARDUINO_USB_CDC_ON_BOOT flag rather than explicit CONFIG_IDF_TARGET checks, because not all development boards for chips with native USB capability (ESP32-C3/C5/C6/S2/S3/H2/P4) actually use the native USB—many have external UART bridge chips instead. The ARDUINO_USB_CDC_ON_BOOT flag correctly indicates the board's actual USB configuration.

Learnt from: softhack007
Repo: wled/WLED PR: 5107
File: boards/adafruit_matrixportal_esp32s3.json:1-66
Timestamp: 2025-11-22T20:33:14.840Z
Learning: In WLED, board JSON files in the boards/ directory may reference partition files that don't exist or have slightly different names than actual files in tools/. This is intentional because platformio.ini or platformio_override.sample.ini explicitly override the partition file using the board_build.partitions setting, which takes precedence over the board JSON partition reference. This pattern exists in multiple local board definitions and should not be flagged as an issue.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T11:14:24.395Z
Learning: In WLED code reviews, verify that all global variables in .cpp files are properly declared: check that they are defined via .h file or via "extern" declaration, verify that declarations are not duplicated, and ensure they are not implicitly declared as "int" (which can happen when the type is omitted).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T17:17:04.657Z
Learning: In WLED code reviews, when C-style functions or variables are added or modified, check if they are globally visible (not static). If the function/variable is not declared in any global header file (like fcn_declare.h), suggest either: (1) making it static (visible only within the translation unit) with a forward declaration if needed, or (2) adding a comment to clarify that the function/variable is intentionally global. This helps reduce global namespace pollution and enables better compiler optimizations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T14:38:09.949Z
Learning: In WLED code reviews, check that FastLED noise function aliases (`inoise8`, `inoise16`, etc.) are not used. These should be replaced with the proper WLED functions (`perlin8`, `perlin16`, etc.) as the `inoise*` functions are only aliases kept for compatibility reasons.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/wled_eeprom.cpp:0-0
Timestamp: 2025-09-01T10:26:17.959Z
Learning: In WLED PR `#4876`, the DMXStartLED EEPROM backward compatibility issue was partially addressed by keeping it at address 2550 and reading it as a 16-bit value, with DMXChannelsValue array moved to addresses 2552-2566. This maintains compatibility with pre-0.11 EEPROM layouts for DMXStartLED, though legacy "Set to 255" (code 6) configurations may still need migration logic.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED PR `#5267`, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.

Learnt from: willmmiles
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1183-1194
Timestamp: 2025-09-18T03:17:30.107Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), digitalCount is intentionally incremented even for placeholder buses to maintain consistent resource mapping across all bus configurations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

Learnt from: willmmiles
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1183-1194
Timestamp: 2025-09-18T03:17:30.107Z
Learning: In WLED bus management code, dead code branches in error handling (like unreachable else breaks) are intentionally preserved to accommodate potential future API changes, even when currently unreachable.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-19T10:36:46.916Z
Learning: When "Calculate CCT from RGB" mode (_cct < 0) is combined with "Accurate white" mode (RGBW_MODE_AUTO_ACCURATE), there is a bug in WLED's bus_manager.cpp where approximateKelvinFromRGB() receives RGB values that have already been modified (r -= w, g -= w, b -= w) by autoWhiteCalc(), causing incorrect Kelvin temperature estimation. The original color is not preserved, and calculateCCT() is called after autoWhiteCalc() modifies the RGB values. This affects BusDigital::setPixelColor() execution order (lines 245, 275).

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:31-36
Timestamp: 2025-09-02T01:45:58.047Z
Learning: For the NeoEsp32RmtHI driver, RISC-V ESP32-C3 support is currently disabled via bus_wrapper.h rather than compile-time guards, as the maintainer willmmiles is working on resolving underlying nested interrupt issues and prefers to centralize the workaround in one location.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:173-180
Timestamp: 2025-09-02T01:56:43.841Z
Learning: willmmiles prefers to maintain consistency with upstream NeoPixelBus patterns (like unchecked malloc in construct() methods) rather than diverging until improvements are made upstream first, to minimize maintenance burden and keep the codebase aligned.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h:72-85
Timestamp: 2025-09-02T01:48:16.409Z
Learning: In NeoPixelBus driver code, ESP_ERROR_CHECK (which can abort) is used in destructors when driver uninstall failures indicate hardware is in an unsafe configuration, as such errors are considered unrecoverable hardware safety issues rather than typical software errors.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/data/index.js:2406-2413
Timestamp: 2025-09-28T09:53:42.670Z
Learning: In WLED, code paths that appear unreachable may actually be safety fallbacks for low-heap conditions. These fallbacks are intentional defensive programming measures to ensure UI functionality is preserved when system resources are constrained.

@softhack007
Copy link
Member

@jonny190 there seems to be a bug in your NPB fork, please check #5048 (comment).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
usermods/audioreactive/audio_source.h (1)

25-33: ⚠️ Potential issue | 🟡 Minor

Stale #error / #warning message text mentions only C2 and C3.

Adding CONFIG_IDF_TARGET_ESP32C61 to the guard is semantically correct (RISC-V, single-core, no hardware FPU like its C6 sibling), but the error and warning messages on lines 30 and 32 still name only ESP32-C2 or ESP32-C3 while the guard now covers seven variants (C2, C3, C5, C6, C61, H2, ESP8266/8265). Any developer who hits either diagnostic on a C5, C6, or C61 board will be misled. This was already a pre-existing issue for C5/C6/H2 before this PR; adding C61 makes it one step worse.

✏️ Suggested message update
  `#if` !defined(SOC_I2S_NUM) || (SOC_I2S_NUM < 1)
- `#error` This audio reactive usermod does not support ESP32-C2 or ESP32-C3.
+ `#error` This audio reactive usermod is not supported on this MCU (no I2S peripheral available).
  `#else`
- `#warning` This audio reactive usermod does not support ESP32-C2 and ESP32-C3.
+ `#warning` This audio reactive usermod has limited support on this MCU (no hardware FPU, single core – expect degraded performance).
  `#endif`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_source.h` around lines 25 - 33, The preprocessor
diagnostics in the audio_source.h block are stale: the `#error` and `#warning`
messages still say "ESP32-C2 or ESP32-C3" even though the guard now covers
CONFIG_IDF_TARGET_ESP32C2, CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5,
CONFIG_IDF_TARGET_ESP32C6, CONFIG_IDF_TARGET_ESP32C61,
CONFIG_IDF_TARGET_ESP32H2, ESP8266 and ESP8265; update the text in the `#error`
and `#warning` lines to either list all affected targets (C2, C3, C5, C6, C61, H2,
ESP8266/ESP8265) or use a general phrase like "these single-core/RISC-V/no-FPU
targets" so the diagnostic accurately reflects the condition checked by the
surrounding `#if` that also references SOC_I2S_NUM.
wled00/pin_manager.cpp (1)

249-271: ⚠️ Potential issue | 🔴 Critical

Add CONFIG_IDF_TARGET_ESP32C61 block to isPinOk — but use correct pin assignments for C61, not C6 pins.

C61 is currently missing from the #elif chain and would fall through to the classic ESP32 handler when built. However, the proposed C61 block is incorrect: C61 does not use GPIO 24–30 for SPI flash. According to Espressif's official documentation, C61 has GPIO 0–29 only and uses GPIO 14–17 and GPIO 19–21 as the primary SPI0/1 pins (typically for flash/PSRAM), making it more similar to classic ESP32 than to C6.

Add:

Proposed C61 block (with correct pin assignments)
+#elif defined(CONFIG_IDF_TARGET_ESP32C61)
+  // ESP32-C61: SPI0/1 pins are GPIO 14-17, 19-21 (used for flash/PSRAM)
+  if ((gpio > 13 && gpio < 18) || (gpio > 18 && gpio < 22)) return false;  // GPIO 14-17, 19-21 for SPI
+  `#if` ARDUINO_USB_CDC_ON_BOOT == 1 || ARDUINO_USB_DFU_ON_BOOT == 1
+  if (gpio == 12 || gpio == 13) return false;   // GPIO 12-13 USB-JTAG
+  `#endif`
 `#else`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/pin_manager.cpp` around lines 249 - 271, The isPinOk function lacks a
CONFIG_IDF_TARGET_ESP32C61 branch and currently falls through to the
classic-ESP32 handler; add an `#elif` block for CONFIG_IDF_TARGET_ESP32C61 in the
same region that marks the correct SPI/PSRAM pins as unavailable (treat GPIO
14–17 and 19–21 as reserved for SPI0/1/PSRAM as per Espressif docs), handle GPIO
16 and 17 with psramFound() semantics similar to existing checks (16 returns
!psramFound(), 17 returns true for specific exceptions else !psramFound()), and
ensure other pins fall back to the classic behavior so the new branch prevents
incorrect marking of GPIO 24–30 as flash pins; reference isPinOk, gpio,
psramFound(), and ESP.getChipModel() when adding the block.
wled00/bus_manager.cpp (1)

1151-1171: ⚠️ Potential issue | 🟡 Minor

I2S DMA buffer estimate may miss single‑I2S bus placement.
The memory calculation still keys off digitalCount <= 8 / == 1, which doesn’t align with the single‑I2S bus now being placed at the end (e.g., ESP32 bus 8, S2 bus 4). Consider deriving the I2S‑using bus from the actual bus index or a PolyBus helper instead of the count heuristic.

Based on learnings: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_manager.cpp` around lines 1151 - 1171, The DMA buffer size logic
incorrectly uses a running digitalCount heuristic to decide which bus uses I2S
(checks with PolyBus::isParallelI2S1Output() && digitalCount <= 8 or
digitalCount == 1), which fails when the single‑I2S bus is placed at the end;
instead determine the I2S‑using bus explicitly (by bus index or a PolyBus
helper) and only apply the i2sCommonSize/maxI2S update for that specific bus.
Replace the digitalCount-based decision inside the loop (symbols: digitalCount,
PolyBus::isParallelI2S1Output(), bus->isDigital(), bus->is2Pin(), maxI2S,
bus->getLength(), bus->getNumberOfChannels(), bus->is16bit()) with logic that
either queries a PolyBus API like getI2SBusIndex()/isI2SOutput() or computes the
I2S bus as the last digital non‑2pin when single‑I2S mode is active, then
compute i2sCommonSize only for that identified bus and update maxI2S.
wled00/FX_fcn.cpp (1)

1194-1211: ⚠️ Potential issue | 🟠 Major

I2S memory estimation still assumes single‑I2S is bus #1.

Line 1196 uses digitalCount == 1 to detect single‑I2S, but single‑I2S is now placed on the last digital bus (ESP32 bus 8 / ESP32‑S2 bus 4). This will miss I2S buffers and under‑estimate maxI2S, allowing oversized configs. Please align usesI2S with the actual single‑I2S bus index per target (or reuse the same mapping logic/constants used for bus allocation).

Based on learnings: In WLED PR #5267, single I2S moved to bus 8 on ESP32 (digitalCount=9) and bus 4 on ESP32‑S2 (digitalCount=5); memory estimation must reflect that.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/FX_fcn.cpp` around lines 1194 - 1211, The usesI2S detection wrongly
treats single‑I2S as digitalCount==1; update the logic so single‑I2S is detected
by the actual single‑I2S bus index (e.g. the last digital bus) instead of
hardcoding 1: change the condition that computes usesI2S to check the bus index
against the single‑I2S mapping (for example compare bus.index == digitalCount-1
or call the shared mapping/constant used for bus allocation), keeping the rest
of the block (Bus::isDigital(bus.type), Bus::is2Pin(bus.type), the stepFactor
and i2sCommonSize calculation) intact so maxI2S is correctly estimated (see
symbols usesI2S, digitalCount, bus.index, Bus::isDigital, Bus::is2Pin, maxI2S).
wled00/wled.h (1)

334-344: ⚠️ Potential issue | 🟠 Major

Simplify RX/TX pin detection to prevent compilation failure on ESP32 variants without framework pin definitions.

The current condition short-circuits on non-classic ESP32 targets (C3/S3/C6/etc), entering the if-block without verifying that RX and TX macros are actually defined. This contradicts the code comment acknowledging that "some arduino variants don't define RX and TX" and will cause compilation failures on any non-classic board that omits these definitions.

Replace with the simpler and safer condition:

`#if` defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)

This ensures RX/TX macros are always verified before use, while boards lacking these definitions safely fall back to the defaults (3, 1).

Proposed fix
-#if defined(ARDUINO_ARCH_ESP32) && (!defined(CONFIG_IDF_TARGET_ESP32) || (defined(RX) && defined(TX)))
+#if defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled.h` around lines 334 - 344, The conditional that selects RX/TX
pins can incorrectly assume RX/TX exist on non-classic ESP32 variants; update
the preprocessor check so RX and TX are only used when actually defined by
changing the if condition to require both RX and TX (i.e., use
"defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)"), ensuring the
existing constexpr variables hardwareRX and hardwareTX fall back to 3 and 1 when
RX/TX are not defined.
♻️ Duplicate comments (13)
platformio.ini (2)

539-539: ⚠️ Potential issue | 🟡 Minor

-D WLED_DEBUG in the esp32c5dev CI artifact — is this intentional?

[env:esp32c5dev] is in default_envs (Line 31), so CI publishes a debug build as a downloadable firmware artifact. Debug builds are larger and emit verbose serial output. For an explicitly EXPERIMENTAL target, this may be a deliberate choice to aid hardware testers, but it should be documented with a comment and removed once the target stabilises.

If this is temporary, add a comment and track removal
   -D WLED_DISABLE_ESPNOW         ;; not yet tested
-  -D WLED_DEBUG
+  -D WLED_DEBUG                  ;; TODO: remove once esp32c5 target is stable
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platformio.ini` at line 539, The esp32c5dev CI artifact currently defines the
debug macro (-D WLED_DEBUG) under the [env:esp32c5dev] configuration which is
included in default_envs, causing a debug firmware to be published; either
remove the -D WLED_DEBUG flag from the esp32c5dev environment in platformio.ini
to produce a release build, or if this is intentional while experimental, add an
inline comment next to the -D WLED_DEBUG entry referencing why it’s present and
a TODO with an issue/PR number to remove it once the target stabilizes; locate
the flag under the [env:esp32c5dev] block and update accordingly, and ensure
default_envs (the list that includes esp32c5dev) remains accurate.

420-420: Pin the C5 NeoPixelBus fork to a commit hash for reproducible builds; verify repository availability.

The current reference https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable uses a branch name. Branches can be force-pushed or deleted, breaking future builds silently. The CI artifact firmware-esp32c5dev (1.14 MB) does confirm the repository is currently reachable, but production-quality builds should pin to a specific commit hash.

Additionally, per the PR discussion, the fork has a known driver bug (RMT constructor ignores the requested channel; allocates channels 2–3 which are RX-only on C5, causing the second WS2812B output to fail). The bug fix mentioned in the PR comments should be tracked for inclusion before this experimental target is promoted.

-  https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable ;; wled-c5-stable for C5 support: I2S exclusion, bit-bang CSR/GPIO, channel ctor overload
+  https://github.com/jonny190/NeoPixelBus.git#<commit-hash>  ;; pin to specific commit for reproducibility; wled-c5-stable branch
github jonny190/NeoPixelBus wled-c5-stable ESP32-C5 NeoPixelBus fork
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platformio.ini` at line 420, Replace the branch reference
"https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable" in platformio.ini
with a pinned commit hash (e.g.
"https://github.com/jonny190/NeoPixelBus.git#<commit-hash>") to ensure
reproducible builds, verify the commit hash exists and the repository is
reachable (the CI artifact "firmware-esp32c5dev" confirms current reachability),
and add a short TODO/note near that dependency to track the NeoPixelBus C5
driver bug (RMT constructor channel allocation issue affecting the second
WS2812B output) so we can update the pinned hash when the upstream bugfix is
published.
wled00/src/dependencies/dmx/SparkFunDMX.cpp (1)

20-20: ⚠️ Potential issue | 🟡 Minor

Two items from the prior review remain unresolved on this line.

Both were previously flagged (and marked ✅ addressed) but are still present in the current code:

  1. !defined(ESP8266) is redundant — the outer #if defined(ARDUINO_ARCH_ESP32) guard on Line 17 already excludes ESP8266; this term can never be true inside that block.

  2. CONFIG_IDF_TARGET_ESP32P4 is missing from the exclusion list — the [esp32p4] section in platformio.ini disables both WLED_ENABLE_DMX_INPUT and WLED_ENABLE_DMX via build_unflags, but SparkFunDMX.cpp will still compile for P4. Since P4 has SOC_UART_NUM >= 3, the #error safety net on Line 46 won't catch it. More critically, the initRead() path uses the legacy timerBegin/timerAttachInterrupt/timerAlarmWrite/timerAlarmEnable API (Lines 86–89), which may fail to compile under the IDF V5 pioarduino platform used for P4.

Proposed fix
-#if !defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C61) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C61) && !defined(CONFIG_IDF_TARGET_ESP32P4) && !defined(CONFIG_IDF_TARGET_ESP32S2)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/src/dependencies/dmx/SparkFunDMX.cpp` at line 20, The preprocessor
exclusion on the SparkFunDMX.cpp top block is incorrect: remove the redundant
!defined(ESP8266) from the `#if` condition (it's already inside the
ARDUINO_ARCH_ESP32 guard) and add CONFIG_IDF_TARGET_ESP32P4 to the list of
excluded targets so the file won't compile for ESP32-P4; additionally ensure the
legacy initRead() path (which uses
timerBegin/timerAttachInterrupt/timerAlarmWrite/timerAlarmEnable) is not
compiled for P4 by the updated `#if` so the IDF v5/incompatible timer APIs are
avoided. Locate the conditional that begins with the current `#if` and update it
to drop ESP8266 and include CONFIG_IDF_TARGET_ESP32P4, keeping the intent of
excluding unsupported targets.
wled00/data/index.js (1)

705-706: ⚠️ Potential issue | 🟡 Minor

Avoid “Ch undefined” when channel is absent.

If i.wifi.band exists but i.wifi.channel is missing, the UI renders “Ch undefined”. Add a band‑only fallback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/data/index.js` around lines 705 - 706, The UI shows "Ch undefined"
when i.wifi.band exists but i.wifi.channel is missing; update the template line
that calls inforow for WiFi band so it checks i.wifi.channel and renders either
"WiFi band" with band + " (Ch <channel>)" when present, or just the band label
when i.wifi.channel is falsy. Modify the second expression that uses
inforow("WiFi band", i.wifi.band + " (Ch " + i.wifi.channel + ")") to branch on
i.wifi.channel (while still verifying i.wifi.band) so inforow receives a
band‑only fallback string when channel is undefined.
usermods/audioreactive/audio_reactive.cpp (3)

2072-2074: ⚠️ Potential issue | 🟠 Major

_analogmic definition guard still mismatches its declaration.

The definition is guarded by ARDUINO_ARCH_ESP32 (with exclusions) while the declaration now uses CONFIG_IDF_TARGET_ESP32. On C5/C6 this can produce a definition without a declaration. Use the same guard on both.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 2072 - 2074, The
definition of AudioReactive::_analogmic is wrapped in a different preprocessor
condition than its declaration; update the `#if/`#endif around the _analogmic
definition to use the exact same guard used for the declaration (i.e., the
CONFIG_IDF_TARGET_ESP32-based condition with the same exclusions) so the
declaration and definition are compiled under the same target conditions and no
orphan definition is produced for AudioReactive::_analogmic.

1163-1231: ⚠️ Potential issue | 🟠 Major

ESP32‑C6 is still missing from these exclusion guards.

These blocks exclude C3/C5 but not C6, so C6 can still hit the PERIPH_I2S0 reset / PDM / ADC paths that are unsupported. Please add CONFIG_IDF_TARGET_ESP32C6 (or switch to a positive classic‑ESP32 guard).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 1163 - 1231, The
build guards missing CONFIG_IDF_TARGET_ESP32C6 allow ESP32‑C6 to enter
unsupported I2S/PDM/ADC paths; update the preprocessor conditions that currently
check CONFIG_IDF_TARGET_ESP32S2, CONFIG_IDF_TARGET_ESP32C3,
CONFIG_IDF_TARGET_ESP32C5 (the blocks around the periph_module_reset call, the
dmType PDM detection if-statement, the switch(dmType) stub cases and the ADC
case creating I2SAdcSource) to also exclude CONFIG_IDF_TARGET_ESP32C6 (or invert
to a positive check for classic ESP32), so paths that call periph_module_reset,
treat dmType==5 as PDM, or create I2SAdcSource are not compiled for C6.

1800-1953: ⚠️ Potential issue | 🟠 Major

Analog‑mic config/UI guards still omit ESP32‑C6.

The analog mic JSON/UI blocks should be classic‑ESP32 only; missing C6 keeps unsupported options enabled on C6. Use CONFIG_IDF_TARGET_ESP32 (or add C6 to the exclusions) for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 1800 - 1953, The
preprocessor guards around the analog-mic JSON/UI (the `#if` blocks that create
amic via FPSTR(_analogmic) in addToConfig and the corresponding UI prints in
appendConfigData) exclude ESP32S2/C3/C5/S3 but omit ESP32C6, leaving unsupported
analog options enabled on C6; update those conditionals to either use
CONFIG_IDF_TARGET_ESP32 (so only classic ESP32 includes analog mic code) or add
CONFIG_IDF_TARGET_ESP32C6 to the exclusion list, and apply the same fix to the
matching guards in readFromConfig, addToConfig (FPSTR(_analogmic) creation) and
appendConfigData (uiScript prints related to analog mic and MCLK info) so all
analog-mic handling is consistently disabled on unsupported MCUs.
wled00/bus_manager.cpp (1)

1261-1264: Comment doesn’t list C61.

✏️ Suggested fix
-  // ESP32-C5/C6/P4 use shared RMT method - idle level inversion not supported
+  // ESP32-C5/C6/C61/P4 use shared RMT method - idle level inversion not supported
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_manager.cpp` around lines 1261 - 1264, The comment above the
preprocessor check is missing "C61" while the `#if` condition includes
CONFIG_IDF_TARGET_ESP32C61; update the comment for the block containing the
preprocessor line "#if defined(CONFIG_IDF_TARGET_ESP32C5) ||
defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) ||
defined(CONFIG_IDF_TARGET_ESP32P4)" in bus_manager.cpp so it reads something
like "ESP32-C5/C6/C61/P4 use shared RMT method - idle level inversion not
supported" to accurately reflect the condition in that block.
wled00/data/settings_wifi.htm (1)

253-275: ⚠️ Potential issue | 🟡 Minor

Regenerate embedded UI headers after this change.
Please run the UI build step so embedded headers stay in sync with the updated page.

As per coding guidelines: “wled00/data/**: When modifying web UI files, run npm run build to regenerate embedded headers before any firmware build.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/data/settings_wifi.htm` around lines 253 - 275, You updated the WiFi
UI controls (elements with id="bm" and id="tx", selects name="BM" and "TX") in
the embedded web page; run the UI build step (npm run build) to regenerate the
embedded UI headers so the firmware binary includes the updated headers before
the next firmware build.
wled00/bus_wrapper.h (1)

1375-1377: RMT-channel comment still doesn’t match the expanded target list.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_wrapper.h` around lines 1375 - 1377, The inline comment above the
condition that returns I_NONE for num > 1 is outdated relative to the expanded
target list; update the comment that currently reads "On ESP32-C3/C5/C6 only the
first 2 RMT channels are usable for transmitting" to accurately list all targets
in the `#elif` (e.g., ESP32-C3/C5/C6/C61/P4) or rephrase to a generic statement
("On these targets only the first 2 RMT channels are usable for transmitting")
so it matches the condition that checks defined(CONFIG_IDF_TARGET_ESP32C3) ||
defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) ||
defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4) and
the num > 1 return I_NONE logic.
wled00/wled_boards.h (2)

74-84: ⚠️ Potential issue | 🟡 Minor

Comment on line 81 still references "esp32-S3" instead of "esp32-S2".

The WLED_BOARD assignment on line 83 was corrected to NODE_TYPE_ID_ESP32S2, but the comment on line 81 still says "esp32-S3 supports I2S parallel leds driver." This should read "esp32-S2."

✏️ Suggested fix
-  `#define` WLED_HAS_PARALLEL_I2S 1    // esp32-S3 supports I2S parallel leds driver (NeoPixelBus)
+  `#define` WLED_HAS_PARALLEL_I2S 1    // esp32-S2 supports I2S parallel leds driver (NeoPixelBus)

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled_boards.h` around lines 74 - 84, The comment for
CONFIG_IDF_TARGET_ESP32S2 incorrectly mentions "esp32-S3"; update the inline
comment that precedes the WLED_HAS_PARALLEL_I2S macro so it refers to "esp32-S2"
(i.e., change the text near the WLED_HAS_PARALLEL_I2S definition within the
CONFIG_IDF_TARGET_ESP32S2 block) to match the corrected WLED_BOARD =
NODE_TYPE_ID_ESP32S2 and avoid confusing references to S3.

130-136: ⚠️ Potential issue | 🟡 Minor

ESP32-P4: "TBC" comments should be resolved.

Lines 133 and 135 still have "TBC" (to be confirmed) markers. Per ESP-IDF documentation, ESP32-P4 does support RTC FAST memory and has fast integer division (dual-core RISC-V with hardware multiply/divide). These markers are stale and should be cleaned up.

✏️ Suggested fix
-  // TBC: is bitshift with rounding is faster than integer division ?
-  `#define` WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division
+  `#define` WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division)
-  `#define` WLED_HAVE_RTC_MEMORY_HEAP 1 // TBC: does it have byte-accessible fast RTC memory that can be used as heap ?
+  `#define` WLED_HAVE_RTC_MEMORY_HEAP 1 // has byte-accessible fast RTC memory that can be used as heap

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled_boards.h` around lines 130 - 136, The comments marked "TBC" on
the ESP32-P4 capability defines are stale — remove the "TBC" markers and make
the defines explicit: keep `#define` WLED_HAVE_FAST_FLOAT 1, keep `#define`
WLED_HAVE_FAST_int_DIVIDE 1 (hardware integer divide available), and keep
`#define` WLED_HAVE_RTC_MEMORY_HEAP 1 (RTC fast memory supported); update the
inline comments next to WLED_HAVE_FAST_int_DIVIDE and WLED_HAVE_RTC_MEMORY_HEAP
to state the confirmed behavior (e.g., "hardware integer divide" and "RTC fast
memory available") and delete the "TBC" text so the intent is clear.
wled00/json.cpp (1)

705-709: deviceId remains absent from JSON on ESP-IDF V5+ builds.

The entire #else block is commented out, meaning IDF V5 devices emit no deviceId field. The UI code (index.js:3390) assigns infoData.deviceId without a fallback, which will pass undefined to the upgrade reporting endpoint. At minimum, emit an empty string or placeholder so the field is always present.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/json.cpp` around lines 705 - 709, The `#else` block currently leaves out
root["deviceId"] entirely on ESP-IDF V5+ builds; ensure the JSON always contains
the deviceId key by adding a fallback assignment in the same spot (set
root[F("deviceId")] to an empty string or a fixed placeholder when
getBootloaderSHA256Hex() is not used), e.g. add a line that assigns an empty
String to root["deviceId"] so code referencing infoData.deviceId in index.js
always gets a defined value; look for the root[...] assignment and
getBootloaderSHA256Hex() usage in json.cpp to place the fallback.
🧹 Nitpick comments (5)
wled00/ota_update.cpp (1)

439-445: C5 validation block follows the established pattern — looks correct.

The code correctly mirrors the existing unsupported-target pattern (C3/S3/C6). One forward-looking concern: when bootloader OTA is eventually enabled for C5, the hardcoded bootloaderOffset = 0x1000 in BootloaderUpdateContext (line 556) will be incorrect — C5 uses BOOTLOADER_OFFSET = 0x2000 (line 18). Consider using the BOOTLOADER_OFFSET constant instead of the hardcoded value when that time comes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/ota_update.cpp` around lines 439 - 445, The C5 validation is fine but
future-enabling OTA for ESP32-C5 requires using the BOOTLOADER_OFFSET constant
rather than the hardcoded 0x1000; update the BootloaderUpdateContext (replace
the hardcoded bootloaderOffset = 0x1000) to reference BOOTLOADER_OFFSET so the
correct 0x2000 value applies for ESP32-C5 (and keeps behavior consistent across
targets).
wled00/bus_wrapper.h (1)

502-513: Resolve or track the TODO in the channel remap block.

Line 509 adds a TODO for simplifying the guard—please either complete it in this PR or link it to an issue so it doesn’t get lost.

If you want, I can draft a consolidated guard using the capability macros.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_wrapper.h` around lines 502 - 513, The TODO about simplifying the
long ifdef guard in the channel remap block must be resolved: either replace the
two separate guards with a single consolidated guard (e.g., define and use a
capability macro that expresses "classic ESP32 I2S1 remap" and then use that
macro to wrap both the parallel-I2S adjustment and the I2S1 subtraction) or
record a tracked issue and reference it in the comment; update the block around
`_useParallelI2S` and the `if (!_useParallelI2S && channel > 0) channel--;`
remap so it uses the new capability macro (or an explicit issue/PR link) instead
of the ad-hoc TODO, ensuring the unique symbols `_useParallelI2S` and `channel`
are handled exactly as before.
wled00/wled_boards.h (1)

18-25: TODO list is useful for tracking remaining capability flags.

The planned macros (WLED_HAVE_TOUCH, WLED_HAVE_I2S0_LEDS, WLED_HAVE_I2S1_LEDS, etc.) will further reduce long #ifdef chains elsewhere. Consider filing a tracking issue so these don't get lost.

Would you like me to open an issue to track the remaining TODO items listed here?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled_boards.h` around lines 18 - 25, Add a tracked issue for the TODO
list in wled_boards.h and reference it in the comment: create an issue that
enumerates the planned macros (WLED_HAVE_TOUCH, WLED_HAVE_I2S0_LEDS,
WLED_HAVE_I2S1_LEDS, the RMT-channel limit flag for ESP32-C3/C5/C6, SparkFunDMX
support flag for ESP32/S3/P4, and WLED_ALLOW_LOLIN_WIFI_FIX) and then update the
TODO block to include the issue number/URL so the items are not lost and future
PRs can link to that tracking issue.
wled00/wled.h (2)

399-404: Note: txPower type mismatch with IDF V5 range.

The TODO on line 403 correctly notes that txPower should be changed to int8_t for IDF V5 (which supports values from WIFI_POWER_21dBm = 84 down to WIFI_POWER_MINUS_1dBm = -4). Currently it's uint8_t, which cannot represent negative values. This is tracked but worth keeping visible.

Would you like me to open an issue to track the txPower type change and UI update needed for IDF V5?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled.h` around lines 399 - 404, The txPower global is declared as
uint8_t which cannot represent IDF V5 negative power values; change the
declaration of WLED_GLOBAL uint8_t txPower _INIT(...) to WLED_GLOBAL int8_t
txPower _INIT(...) in both branches (the LOLIN_WIFI_FIX branch and the else
branch) and then audit/adjust all code and UI paths that read or write txPower
(serialization, UI widgets, and any arithmetic or comparisons) to handle signed
int8_t values and the extended WIFI_POWER_21dBm/WIFI_POWER_MINUS_1dBm range.

158-165: Duplicate DMX target guards should be centralized.

The same #if defined(CONFIG_IDF_TARGET_ESP32C5) || ... C6 ... C61 ... P4 guard pattern appears at both lines 159 and 481. If a new target is added or an existing one gains DMX support, both locations must be updated in sync. Consider defining a macro like WLED_DMX_UNSUPPORTED_TARGET in wled_boards.h and referencing it in both places.

♻️ Example approach in wled_boards.h
+ // Define in wled_boards.h, in each unsupported target block:
+ `#define` WLED_NO_SPARKFUN_DMX 1  // no SparkFunDMX support on this target

Then in wled.h:

-#if defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)  || defined(CONFIG_IDF_TARGET_ESP32C61)  || defined(CONFIG_IDF_TARGET_ESP32P4)
+#if defined(WLED_NO_SPARKFUN_DMX)
   `#error` "DMX output is not supported on this target (esp_dmx library excluded)"

Also applies to: 481-486

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/wled.h` around lines 158 - 165, The duplicated target guard for DMX
(the long `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || ...
CONFIG_IDF_TARGET_ESP32P4 pattern used when WLED_ENABLE_DMX is enabled) should
be centralized: add a single preprocessor macro WLED_DMX_UNSUPPORTED_TARGET in
the common board header (e.g., declare it via the existing board/target macros)
and replace the long guard in wled.h (both the include-selection block that
checks WLED_ENABLE_DMX and the second occurrence at the later DMX-related block)
with a single check using defined(WLED_DMX_UNSUPPORTED_TARGET); update both
places to use that macro so new targets only need one change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wled00/bus_manager.cpp`:
- Around line 549-561: The duty update path still writes
LEDC.channel_group[gr].channel[ch].duty.duty and hpoint.hpoint directly for many
targets; wrap those direct register writes with the same ESP_IDF_VERSION check
used elsewhere (e.g. use ifdef/if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)
around the LEDC.channel_group[...] assignments and ledc_update_duty call) and
for newer ESP‑IDF versions call the HAL API (ledc_set_duty_and_update) like the
C5/C61/P4 branch does; update the comment/TODO to note dithering handling for P4
and ensure you reference LEDC.channel_group[gr].channel[ch].duty.duty,
LEDC.channel_group[gr].channel[ch].hpoint.hpoint, ledc_update_duty and
ledc_set_duty_and_update when making the change.

In `@wled00/json.cpp`:
- Around line 805-814: The current WiFi band detection calls WiFi.getBand() and
checks SOC_WIFI_SUPPORT_5G which aren’t available in the active core, causing
build failures; update the wifi band handling in the block that fills wifi_info
(referencing WiFi.channel(), wifi_info and the existing `#if`
defined(SOC_WIFI_SUPPORT_5G) branch) so it does not call WiFi.getBand() unless
the build actually provides that API (or a corresponding feature macro),
otherwise fall back to a safe default (e.g., always set wifi_info["band"] =
"2.4GHz" or omit band reporting); in short, remove or guard the WiFi.getBand()
usage behind a reliable feature/version check or replace it with a stable
fallback to ensure compilation in the current build configuration.

In `@wled00/ota_update.cpp`:
- Around line 18-19: Update the stale inline comment on the BOOTLOADER_OFFSET
declaration to list all targets present in the preprocessor condition
(CONFIG_IDF_TARGET_ESP32S3, CONFIG_IDF_TARGET_ESP32C3,
CONFIG_IDF_TARGET_ESP32C6, CONFIG_IDF_TARGET_ESP32C61) so the comment matches
the `#if` clause; also add a note in the comment referencing that
verifyBootloaderImage currently lacks a branch for ESP32C61 and will return
"Unknown ESP32 target - bootloader update not supported" until a validation
branch is added when C61 bootloader updates are enabled.

In `@wled00/wled_boards.h`:
- Around line 44-45: The comments for the WLED_HAVE_FAST_int_DIVIDE macro are
missing a closing parenthesis in several board blocks (the comment text ending
"...no need to use bitshifts with rounding instead of integer division"); update
each occurrence of the WLED_HAVE_FAST_int_DIVIDE comment (ESP32-S3 / ESP32-S2 /
ESP32-P4 blocks) to add the missing ")" so the parenthetical closes properly and
the comment reads correctly.

In `@wled00/wled.h`:
- Around line 396-398: The access to the global variable wifiBandMode in set.cpp
is not guarded by the SOC_WIFI_SUPPORT_5G macro, causing build errors when 5G
support is absent; locate the conditional block that checks/assigns wifiBandMode
(the lines containing "if (bm != wifiBandMode) {" and "wifiBandMode = bm;") and
wrap that entire block with `#ifdef` SOC_WIFI_SUPPORT_5G ... `#endif` (or skip the
assignment/compare when SOC_WIFI_SUPPORT_5G is not defined) so that all
reads/writes to wifiBandMode are compiled only when SOC_WIFI_SUPPORT_5G is
enabled.

In `@wled00/xml.cpp`:
- Around line 322-329: Replace the magic numbers "2, 6" used for C3 emulation
with named constants (e.g., WLED_EMULATED_C3_MAX_DIGITAL_CHANNELS and
WLED_EMULATED_C3_MAX_ANALOG_CHANNELS) and use those in the conditional branch
where isC3 emulation is applied (the block currently substituting for
WLED_MAX_DIGITAL_CHANNELS and WLED_MAX_ANALOG_CHANNELS); add those defines in an
appropriate header if they don't exist, then update any references to keep
intent clear. Also fix indentation so the line with WLED_MAX_BUTTONS uses
2-space indentation consistent with other .cpp files. Ensure symbol names match
project naming conventions and compile.

---

Outside diff comments:
In `@usermods/audioreactive/audio_source.h`:
- Around line 25-33: The preprocessor diagnostics in the audio_source.h block
are stale: the `#error` and `#warning` messages still say "ESP32-C2 or ESP32-C3"
even though the guard now covers CONFIG_IDF_TARGET_ESP32C2,
CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5, CONFIG_IDF_TARGET_ESP32C6,
CONFIG_IDF_TARGET_ESP32C61, CONFIG_IDF_TARGET_ESP32H2, ESP8266 and ESP8265;
update the text in the `#error` and `#warning` lines to either list all affected
targets (C2, C3, C5, C6, C61, H2, ESP8266/ESP8265) or use a general phrase like
"these single-core/RISC-V/no-FPU targets" so the diagnostic accurately reflects
the condition checked by the surrounding `#if` that also references SOC_I2S_NUM.

In `@wled00/bus_manager.cpp`:
- Around line 1151-1171: The DMA buffer size logic incorrectly uses a running
digitalCount heuristic to decide which bus uses I2S (checks with
PolyBus::isParallelI2S1Output() && digitalCount <= 8 or digitalCount == 1),
which fails when the single‑I2S bus is placed at the end; instead determine the
I2S‑using bus explicitly (by bus index or a PolyBus helper) and only apply the
i2sCommonSize/maxI2S update for that specific bus. Replace the
digitalCount-based decision inside the loop (symbols: digitalCount,
PolyBus::isParallelI2S1Output(), bus->isDigital(), bus->is2Pin(), maxI2S,
bus->getLength(), bus->getNumberOfChannels(), bus->is16bit()) with logic that
either queries a PolyBus API like getI2SBusIndex()/isI2SOutput() or computes the
I2S bus as the last digital non‑2pin when single‑I2S mode is active, then
compute i2sCommonSize only for that identified bus and update maxI2S.

In `@wled00/FX_fcn.cpp`:
- Around line 1194-1211: The usesI2S detection wrongly treats single‑I2S as
digitalCount==1; update the logic so single‑I2S is detected by the actual
single‑I2S bus index (e.g. the last digital bus) instead of hardcoding 1: change
the condition that computes usesI2S to check the bus index against the
single‑I2S mapping (for example compare bus.index == digitalCount-1 or call the
shared mapping/constant used for bus allocation), keeping the rest of the block
(Bus::isDigital(bus.type), Bus::is2Pin(bus.type), the stepFactor and
i2sCommonSize calculation) intact so maxI2S is correctly estimated (see symbols
usesI2S, digitalCount, bus.index, Bus::isDigital, Bus::is2Pin, maxI2S).

In `@wled00/pin_manager.cpp`:
- Around line 249-271: The isPinOk function lacks a CONFIG_IDF_TARGET_ESP32C61
branch and currently falls through to the classic-ESP32 handler; add an `#elif`
block for CONFIG_IDF_TARGET_ESP32C61 in the same region that marks the correct
SPI/PSRAM pins as unavailable (treat GPIO 14–17 and 19–21 as reserved for
SPI0/1/PSRAM as per Espressif docs), handle GPIO 16 and 17 with psramFound()
semantics similar to existing checks (16 returns !psramFound(), 17 returns true
for specific exceptions else !psramFound()), and ensure other pins fall back to
the classic behavior so the new branch prevents incorrect marking of GPIO 24–30
as flash pins; reference isPinOk, gpio, psramFound(), and ESP.getChipModel()
when adding the block.

In `@wled00/wled.h`:
- Around line 334-344: The conditional that selects RX/TX pins can incorrectly
assume RX/TX exist on non-classic ESP32 variants; update the preprocessor check
so RX and TX are only used when actually defined by changing the if condition to
require both RX and TX (i.e., use "defined(ARDUINO_ARCH_ESP32) && defined(RX) &&
defined(TX)"), ensuring the existing constexpr variables hardwareRX and
hardwareTX fall back to 3 and 1 when RX/TX are not defined.

---

Duplicate comments:
In `@platformio.ini`:
- Line 539: The esp32c5dev CI artifact currently defines the debug macro (-D
WLED_DEBUG) under the [env:esp32c5dev] configuration which is included in
default_envs, causing a debug firmware to be published; either remove the -D
WLED_DEBUG flag from the esp32c5dev environment in platformio.ini to produce a
release build, or if this is intentional while experimental, add an inline
comment next to the -D WLED_DEBUG entry referencing why it’s present and a TODO
with an issue/PR number to remove it once the target stabilizes; locate the flag
under the [env:esp32c5dev] block and update accordingly, and ensure default_envs
(the list that includes esp32c5dev) remains accurate.
- Line 420: Replace the branch reference
"https://github.com/jonny190/NeoPixelBus.git#wled-c5-stable" in platformio.ini
with a pinned commit hash (e.g.
"https://github.com/jonny190/NeoPixelBus.git#<commit-hash>") to ensure
reproducible builds, verify the commit hash exists and the repository is
reachable (the CI artifact "firmware-esp32c5dev" confirms current reachability),
and add a short TODO/note near that dependency to track the NeoPixelBus C5
driver bug (RMT constructor channel allocation issue affecting the second
WS2812B output) so we can update the pinned hash when the upstream bugfix is
published.

In `@usermods/audioreactive/audio_reactive.cpp`:
- Around line 2072-2074: The definition of AudioReactive::_analogmic is wrapped
in a different preprocessor condition than its declaration; update the
`#if/`#endif around the _analogmic definition to use the exact same guard used for
the declaration (i.e., the CONFIG_IDF_TARGET_ESP32-based condition with the same
exclusions) so the declaration and definition are compiled under the same target
conditions and no orphan definition is produced for AudioReactive::_analogmic.
- Around line 1163-1231: The build guards missing CONFIG_IDF_TARGET_ESP32C6
allow ESP32‑C6 to enter unsupported I2S/PDM/ADC paths; update the preprocessor
conditions that currently check CONFIG_IDF_TARGET_ESP32S2,
CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5 (the blocks around the
periph_module_reset call, the dmType PDM detection if-statement, the
switch(dmType) stub cases and the ADC case creating I2SAdcSource) to also
exclude CONFIG_IDF_TARGET_ESP32C6 (or invert to a positive check for classic
ESP32), so paths that call periph_module_reset, treat dmType==5 as PDM, or
create I2SAdcSource are not compiled for C6.
- Around line 1800-1953: The preprocessor guards around the analog-mic JSON/UI
(the `#if` blocks that create amic via FPSTR(_analogmic) in addToConfig and the
corresponding UI prints in appendConfigData) exclude ESP32S2/C3/C5/S3 but omit
ESP32C6, leaving unsupported analog options enabled on C6; update those
conditionals to either use CONFIG_IDF_TARGET_ESP32 (so only classic ESP32
includes analog mic code) or add CONFIG_IDF_TARGET_ESP32C6 to the exclusion
list, and apply the same fix to the matching guards in readFromConfig,
addToConfig (FPSTR(_analogmic) creation) and appendConfigData (uiScript prints
related to analog mic and MCLK info) so all analog-mic handling is consistently
disabled on unsupported MCUs.

In `@wled00/bus_manager.cpp`:
- Around line 1261-1264: The comment above the preprocessor check is missing
"C61" while the `#if` condition includes CONFIG_IDF_TARGET_ESP32C61; update the
comment for the block containing the preprocessor line "#if
defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) ||
defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4)" in
bus_manager.cpp so it reads something like "ESP32-C5/C6/C61/P4 use shared RMT
method - idle level inversion not supported" to accurately reflect the condition
in that block.

In `@wled00/bus_wrapper.h`:
- Around line 1375-1377: The inline comment above the condition that returns
I_NONE for num > 1 is outdated relative to the expanded target list; update the
comment that currently reads "On ESP32-C3/C5/C6 only the first 2 RMT channels
are usable for transmitting" to accurately list all targets in the `#elif` (e.g.,
ESP32-C3/C5/C6/C61/P4) or rephrase to a generic statement ("On these targets
only the first 2 RMT channels are usable for transmitting") so it matches the
condition that checks defined(CONFIG_IDF_TARGET_ESP32C3) ||
defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) ||
defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4) and
the num > 1 return I_NONE logic.

In `@wled00/data/index.js`:
- Around line 705-706: The UI shows "Ch undefined" when i.wifi.band exists but
i.wifi.channel is missing; update the template line that calls inforow for WiFi
band so it checks i.wifi.channel and renders either "WiFi band" with band + "
(Ch <channel>)" when present, or just the band label when i.wifi.channel is
falsy. Modify the second expression that uses inforow("WiFi band", i.wifi.band +
" (Ch " + i.wifi.channel + ")") to branch on i.wifi.channel (while still
verifying i.wifi.band) so inforow receives a band‑only fallback string when
channel is undefined.

In `@wled00/data/settings_wifi.htm`:
- Around line 253-275: You updated the WiFi UI controls (elements with id="bm"
and id="tx", selects name="BM" and "TX") in the embedded web page; run the UI
build step (npm run build) to regenerate the embedded UI headers so the firmware
binary includes the updated headers before the next firmware build.

In `@wled00/json.cpp`:
- Around line 705-709: The `#else` block currently leaves out root["deviceId"]
entirely on ESP-IDF V5+ builds; ensure the JSON always contains the deviceId key
by adding a fallback assignment in the same spot (set root[F("deviceId")] to an
empty string or a fixed placeholder when getBootloaderSHA256Hex() is not used),
e.g. add a line that assigns an empty String to root["deviceId"] so code
referencing infoData.deviceId in index.js always gets a defined value; look for
the root[...] assignment and getBootloaderSHA256Hex() usage in json.cpp to place
the fallback.

In `@wled00/src/dependencies/dmx/SparkFunDMX.cpp`:
- Line 20: The preprocessor exclusion on the SparkFunDMX.cpp top block is
incorrect: remove the redundant !defined(ESP8266) from the `#if` condition (it's
already inside the ARDUINO_ARCH_ESP32 guard) and add CONFIG_IDF_TARGET_ESP32P4
to the list of excluded targets so the file won't compile for ESP32-P4;
additionally ensure the legacy initRead() path (which uses
timerBegin/timerAttachInterrupt/timerAlarmWrite/timerAlarmEnable) is not
compiled for P4 by the updated `#if` so the IDF v5/incompatible timer APIs are
avoided. Locate the conditional that begins with the current `#if` and update it
to drop ESP8266 and include CONFIG_IDF_TARGET_ESP32P4, keeping the intent of
excluding unsupported targets.

In `@wled00/wled_boards.h`:
- Around line 74-84: The comment for CONFIG_IDF_TARGET_ESP32S2 incorrectly
mentions "esp32-S3"; update the inline comment that precedes the
WLED_HAS_PARALLEL_I2S macro so it refers to "esp32-S2" (i.e., change the text
near the WLED_HAS_PARALLEL_I2S definition within the CONFIG_IDF_TARGET_ESP32S2
block) to match the corrected WLED_BOARD = NODE_TYPE_ID_ESP32S2 and avoid
confusing references to S3.
- Around line 130-136: The comments marked "TBC" on the ESP32-P4 capability
defines are stale — remove the "TBC" markers and make the defines explicit: keep
`#define` WLED_HAVE_FAST_FLOAT 1, keep `#define` WLED_HAVE_FAST_int_DIVIDE 1
(hardware integer divide available), and keep `#define` WLED_HAVE_RTC_MEMORY_HEAP
1 (RTC fast memory supported); update the inline comments next to
WLED_HAVE_FAST_int_DIVIDE and WLED_HAVE_RTC_MEMORY_HEAP to state the confirmed
behavior (e.g., "hardware integer divide" and "RTC fast memory available") and
delete the "TBC" text so the intent is clear.

---

Nitpick comments:
In `@wled00/bus_wrapper.h`:
- Around line 502-513: The TODO about simplifying the long ifdef guard in the
channel remap block must be resolved: either replace the two separate guards
with a single consolidated guard (e.g., define and use a capability macro that
expresses "classic ESP32 I2S1 remap" and then use that macro to wrap both the
parallel-I2S adjustment and the I2S1 subtraction) or record a tracked issue and
reference it in the comment; update the block around `_useParallelI2S` and the
`if (!_useParallelI2S && channel > 0) channel--;` remap so it uses the new
capability macro (or an explicit issue/PR link) instead of the ad-hoc TODO,
ensuring the unique symbols `_useParallelI2S` and `channel` are handled exactly
as before.

In `@wled00/ota_update.cpp`:
- Around line 439-445: The C5 validation is fine but future-enabling OTA for
ESP32-C5 requires using the BOOTLOADER_OFFSET constant rather than the hardcoded
0x1000; update the BootloaderUpdateContext (replace the hardcoded
bootloaderOffset = 0x1000) to reference BOOTLOADER_OFFSET so the correct 0x2000
value applies for ESP32-C5 (and keeps behavior consistent across targets).

In `@wled00/wled_boards.h`:
- Around line 18-25: Add a tracked issue for the TODO list in wled_boards.h and
reference it in the comment: create an issue that enumerates the planned macros
(WLED_HAVE_TOUCH, WLED_HAVE_I2S0_LEDS, WLED_HAVE_I2S1_LEDS, the RMT-channel
limit flag for ESP32-C3/C5/C6, SparkFunDMX support flag for ESP32/S3/P4, and
WLED_ALLOW_LOLIN_WIFI_FIX) and then update the TODO block to include the issue
number/URL so the items are not lost and future PRs can link to that tracking
issue.

In `@wled00/wled.h`:
- Around line 399-404: The txPower global is declared as uint8_t which cannot
represent IDF V5 negative power values; change the declaration of WLED_GLOBAL
uint8_t txPower _INIT(...) to WLED_GLOBAL int8_t txPower _INIT(...) in both
branches (the LOLIN_WIFI_FIX branch and the else branch) and then audit/adjust
all code and UI paths that read or write txPower (serialization, UI widgets, and
any arithmetic or comparisons) to handle signed int8_t values and the extended
WIFI_POWER_21dBm/WIFI_POWER_MINUS_1dBm range.
- Around line 158-165: The duplicated target guard for DMX (the long `#if`
defined(CONFIG_IDF_TARGET_ESP32C5) || ... CONFIG_IDF_TARGET_ESP32P4 pattern used
when WLED_ENABLE_DMX is enabled) should be centralized: add a single
preprocessor macro WLED_DMX_UNSUPPORTED_TARGET in the common board header (e.g.,
declare it via the existing board/target macros) and replace the long guard in
wled.h (both the include-selection block that checks WLED_ENABLE_DMX and the
second occurrence at the later DMX-related block) with a single check using
defined(WLED_DMX_UNSUPPORTED_TARGET); update both places to use that macro so
new targets only need one change.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9232bd4 and 2802f8c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • package.json
  • platformio.ini
  • usermods/audioreactive/audio_reactive.cpp
  • usermods/audioreactive/audio_source.h
  • wled00/FX.h
  • wled00/FX_fcn.cpp
  • wled00/FXparticleSystem.cpp
  • wled00/bus_manager.cpp
  • wled00/bus_wrapper.h
  • wled00/button.cpp
  • wled00/cfg.cpp
  • wled00/const.h
  • wled00/data/index.js
  • wled00/data/settings_wifi.htm
  • wled00/dmx_output.cpp
  • wled00/improv.cpp
  • wled00/json.cpp
  • wled00/ota_update.cpp
  • wled00/pin_manager.cpp
  • wled00/set.cpp
  • wled00/src/dependencies/dmx/ESPDMX.cpp
  • wled00/src/dependencies/dmx/SparkFunDMX.cpp
  • wled00/udp.cpp
  • wled00/util.cpp
  • wled00/wled.cpp
  • wled00/wled.h
  • wled00/wled_boards.h
  • wled00/ws.cpp
  • wled00/xml.cpp
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • wled00/set.cpp
  • wled00/button.cpp
  • wled00/improv.cpp

fixes compiler warning related to ignored attributes

wled00/button.cpp:399:31: warning: ignoring attribute 'section (".iram1.1")' because it conflicts with previous 'section (".iram1.0")' [-Wattributes]
  399 | void IRAM_ATTR touchButtonISR()
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
wled00/bus_manager.cpp (1)

1160-1164: ⚠️ Potential issue | 🟠 Major

Single-I2S DMA accounting still assumes the first digital bus.

The non-parallel branch still checks digitalCount == 1, which can miss the actual single-I2S bus placement and underestimate maxI2S.

🔧 Suggested fix
-      if ((PolyBus::isParallelI2S1Output() && digitalCount <= 8) || (!PolyBus::isParallelI2S1Output() && digitalCount == 1)) {
+      bool usesI2SCommonBuffer = PolyBus::isParallelI2S1Output() && (digitalCount <= 8);
+      if (!PolyBus::isParallelI2S1Output()) {
+#if defined(CONFIG_IDF_TARGET_ESP32)
+        usesI2SCommonBuffer = (digitalCount == 9); // single I2S on logical bus 8
+#elif defined(CONFIG_IDF_TARGET_ESP32S2)
+        usesI2SCommonBuffer = (digitalCount == 5); // single I2S on logical bus 4
+#endif
+      }
+      if (usesI2SCommonBuffer) {

Based on learnings: “In WLED PR #5267, single I2S moved to the end bus (ESP32 bus 8 / S2 bus 4), so memory logic must account for specific bus placement instead of first-bus assumptions.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_manager.cpp` around lines 1160 - 1164, The code currently treats
the single-I2S DMA case as "first digital bus" by checking digitalCount == 1;
change the non-parallel branch to detect whether the current bus is the actual
single-I2S DMA output instead of relying on digitalCount. Replace the
(!PolyBus::isParallelI2S1Output() && digitalCount == 1) check with a call that
identifies the bus as the single-I2S output (for example use bus->isI2S1Output()
or an equivalent method/property that indicates this bus hosts the single I2S
DMA), so the condition becomes ((PolyBus::isParallelI2S1Output() && digitalCount
<= 8) || (!PolyBus::isParallelI2S1Output() && bus->isI2S1Output())) and adjust
any maxI2S accounting accordingly.
wled00/FX_fcn.cpp (1)

1195-1200: ⚠️ Potential issue | 🟠 Major

usesI2S still assumes single-I2S is the first digital bus.

On Line 1196, (!useParallelI2S && digitalCount == 1) can under-estimate maxI2S for layouts where single-I2S is assigned to a later bus. Please derive this from the same bus-placement logic used by allocation, not fixed digitalCount thresholds.

Based on learnings, single I2S placement is target-specific (e.g., tail bus on ESP32/S2), and memory calculation should follow that mapping rather than digitalCount heuristics.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/FX_fcn.cpp` around lines 1195 - 1200, The current usesI2S calculation
assumes single-I2S is bus 0 (using (!useParallelI2S && digitalCount == 1)),
which undercounts maxI2S for layouts where single-I2S is placed on a later bus;
instead derive usesI2S from the same bus-placement mapping used by allocation:
replicate or call the bus-placement logic to compute the index of the single-I2S
bus for the target when useParallelI2S is false (target-specific placement),
then set usesI2S = (useParallelI2S && digitalCount <= 8) || (!useParallelI2S &&
i2sBusIndex < digitalCount), and ensure any maxI2S/memory calculations use that
derived i2sBusIndex rather than digitalCount == 1; update references to usesI2S,
useParallelI2S, digitalCount and maxI2S accordingly.
♻️ Duplicate comments (8)
wled00/ota_update.cpp (1)

18-19: ⚠️ Potential issue | 🟡 Minor

Update the inline target comment to match the preprocessor condition.

Line 19 is stale: it omits ESP32-C61 and still labels C6 as future support while C6 is already included at Line 18.

Suggested comment fix
-constexpr size_t BOOTLOADER_OFFSET = 0x0000; // esp32-S3, esp32-C3 and (future support) esp32-c6
+constexpr size_t BOOTLOADER_OFFSET = 0x0000; // esp32-S3, esp32-C3, esp32-C6, and (future support) esp32-C61
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/ota_update.cpp` around lines 18 - 19, The inline comment next to the
BOOTLOADER_OFFSET definition is stale; update the comment to reflect the
preprocessor condition (`#if` defined(CONFIG_IDF_TARGET_ESP32S3) ||
defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) ||
defined(CONFIG_IDF_TARGET_ESP32C61)) by explicitly listing esp32-S3, esp32-C3,
esp32-C6 and esp32-C61 and removing the "future support" wording for C6 so the
comment accurately matches the condition for BOOTLOADER_OFFSET.
usermods/audioreactive/audio_reactive.cpp (3)

1163-1166: ⚠️ Potential issue | 🔴 Critical

periph_module_reset(PERIPH_I2S0_MODULE) will be called on ESP32-C6.

The guard now correctly skips C3 and C5 but omits C6, which is the same RISC-V family and lacks PERIPH_I2S0_MODULE. Extend the guard:

🔧 Proposed fix
-#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
+#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6)
   delay(100);
   periph_module_reset(PERIPH_I2S0_MODULE);
 `#endif`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 1163 - 1166, The
conditional that skips calling periph_module_reset(PERIPH_I2S0_MODULE) currently
excludes CONFIG_IDF_TARGET_ESP32C3 and CONFIG_IDF_TARGET_ESP32C5 but misses
CONFIG_IDF_TARGET_ESP32C6, so periph_module_reset will be invoked on ESP32-C6
where PERIPH_I2S0_MODULE is unavailable; update the preprocessor guard around
the delay(100) / periph_module_reset block to also check for
CONFIG_IDF_TARGET_ESP32C6 (i.e., add && !defined(CONFIG_IDF_TARGET_ESP32C6) to
the `#if`) so the reset call is skipped on C6 as well.

1906-1915: ⚠️ Potential issue | 🟠 Major

C6 missing from appendConfigData UI option guards — invalid mic types shown on C6.

C6 users would see "Generic Analog" and "Generic I2S PDM" options which are unsupported on C6. Add !defined(CONFIG_IDF_TARGET_ESP32C6) to the three guards in appendConfigData:

🔧 Proposed fix
-  `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+  `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32S3)
     uiScript.print(F("addOption(dd,'Generic Analog',0);"));
   `#endif`

-  `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
+  `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6)
     uiScript.print(F("addOption(dd,'Generic I2S PDM',5);"));
   `#endif`

-  `#if` !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+  `#if` !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32S3)
     uiScript.print(F("addInfo(uxp,3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
   `#else`
     uiScript.print(F("addInfo(uxp,3,'<i>master clock</i>','I2S MCLK');"));
   `#endif`

Also applies to: 1949-1953

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 1906 - 1915,
appendConfigData currently conditionally prints mic type options but omits
CONFIG_IDF_TARGET_ESP32C6, causing unsupported "Generic Analog" and "Generic I2S
PDM" options to appear on C6 devices; update the three preprocessor guards
around uiScript.print calls that output "addOption(dd,'Generic Analog',0);" and
"addOption(dd,'Generic I2S PDM',5);" (appearing near lines where
appendConfigData emits those addOption entries and again around the second block
at ~1949-1953) to also check !defined(CONFIG_IDF_TARGET_ESP32C6) so the guards
become e.g. `#if` !defined(CONFIG_IDF_TARGET_ESP32S2) &&
!defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) &&
!defined(CONFIG_IDF_TARGET_ESP32C6).

1171-1182: ⚠️ Potential issue | 🟠 Major

C6 missing from PDM auto-detect and stub case guards.

C6 lacks PDM and ADC-over-I2S support (same as C3/C5). Three guards here need C6 added:

  • Line 1171 (PDM auto-detect exclusion): add !defined(CONFIG_IDF_TARGET_ESP32C6)
  • Line 1176 (outer stub cases): add || defined(CONFIG_IDF_TARGET_ESP32C6)
  • Line 1179 (inner PDM stub): add || defined(CONFIG_IDF_TARGET_ESP32C6)
🔧 Proposed fix
-#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
+#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6)
   if ((i2sckPin == I2S_PIN_NO_CHANGE) && ...) dmType = 5;
 `#endif`

-#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32S3)
+#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3)
   case 0:
-  `#if` defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
+  `#if` defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)
   case 5:
   `#endif`
 `#endif`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@usermods/audioreactive/audio_reactive.cpp` around lines 1171 - 1182, The
preprocessor guards omit ESP32C6 causing PDM/ADC-over-I2S to be incorrectly
enabled on C6; update the three conditionals to include
CONFIG_IDF_TARGET_ESP32C6: add !defined(CONFIG_IDF_TARGET_ESP32C6) to the PDM
auto-detect exclusion that checks i2sckPin/i2ssdPin/i2swsPin/dmType, add ||
defined(CONFIG_IDF_TARGET_ESP32C6) to the outer stub guard that wraps the switch
cases for dmType, and add || defined(CONFIG_IDF_TARGET_ESP32C6) to the inner PDM
stub guard so case 5 (PDM Microphone) is correctly excluded on C6.
wled00/src/dependencies/dmx/SparkFunDMX.cpp (1)

20-20: ⚠️ Potential issue | 🟡 Minor

Redundant !defined(ESP8266) and missing CONFIG_IDF_TARGET_ESP32P4 exclusion still present.

These were flagged in a prior review and marked as addressed, but the current code still has both issues:

  1. !defined(ESP8266) is dead weight — ESP8266 is never defined when ARDUINO_ARCH_ESP32 is active (line 17).
  2. CONFIG_IDF_TARGET_ESP32P4 is absent — wled.h routes P4 to the ESPDMX path, so SparkFunDMX compiles for P4 unnecessarily, producing dead code.
🔧 Proposed fix
-#if !defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C61) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C61) && !defined(CONFIG_IDF_TARGET_ESP32P4) && !defined(CONFIG_IDF_TARGET_ESP32S2)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/src/dependencies/dmx/SparkFunDMX.cpp` at line 20, The preprocessor
condition in SparkFunDMX.cpp still redundantly tests !defined(ESP8266) and omits
CONFIG_IDF_TARGET_ESP32P4; update the guard that starts with `#if`
!defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32C3)... to remove the
!defined(ESP8266) term and add && !defined(CONFIG_IDF_TARGET_ESP32P4) so
SparkFunDMX (SparkFunDMX.cpp) is excluded for the ESP32P4 target and avoids
compiling unnecessary dead code.
wled00/xml.cpp (1)

322-329: Replace temporary 2, 6 literals with named constants (and fix comment typo).

This is still readable enough for now, but named constants make the emulation intent clearer and safer to maintain.

♻️ Proposed cleanup
 `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4)
-      // pretend to be a C3 - temporary hack to keep seetings_leds working -> isC3() =>  maxD ==  2 && maxA ==  6
-      2, 6, 
+      constexpr uint8_t kUiMaxDigitalChannels = 2;
+      constexpr uint8_t kUiMaxAnalogChannels  = 6;
+      // pretend to be a C3 - temporary hack to keep settings_leds working -> isC3() => maxD == 2 && maxA == 6
+      kUiMaxDigitalChannels, kUiMaxAnalogChannels,
 `#else`
       WLED_MAX_DIGITAL_CHANNELS,
       WLED_MAX_ANALOG_CHANNELS,
 `#endif`
-		WLED_MAX_BUTTONS
+      WLED_MAX_BUTTONS

Based on learnings: “In WLED code reviews, when code is modified or added, look for ‘magic numbers’ (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR.”
As per coding guidelines: “wled00/**/*.cpp: Use 2-space indentation for C++ source files (.cpp)”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/xml.cpp` around lines 322 - 329, Replace the magic literals "2, 6"
with named constants to clarify the C3 emulation intent and fix the comment
typo; instead of hardcoded values use the existing symbols (e.g.,
WLED_MAX_DIGITAL_CHANNELS and WLED_MAX_ANALOG_CHANNELS or define
WLED_EMULATED_C3_MAX_DIGITAL / WLED_EMULATED_C3_MAX_ANALOG if clearer) in the
conditional block that pretends to be a C3 (the comment referencing isC3());
also correct the comment text from "seetings_leds" to "settings_leds" so the
purpose is clear and maintainable while keeping WLED_MAX_BUTTONS unchanged.
wled00/bus_manager.cpp (1)

1261-1263: ⚠️ Potential issue | 🟡 Minor

Keep the idle-inversion comment aligned with its guard.

The guard includes CONFIG_IDF_TARGET_ESP32C61, but the comment text omits C61.

✏️ Suggested fix
-  // ESP32-C5/C6/P4 use shared RMT method - idle level inversion not supported
+  // ESP32-C5/C6/C61/P4 use shared RMT method - idle level inversion not supported
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_manager.cpp` around lines 1261 - 1263, The preprocessor guard that
checks CONFIG_IDF_TARGET_ESP32C61 is missing from the inline comment—update the
comment above the return in bus_manager.cpp (the line with `#if`
defined(...CONFIG_IDF_TARGET_ESP32C61...)) so it lists ESP32-C61 alongside
ESP32-C5/C6/P4 (e.g., "ESP32-C5/C6/C61/P4 use shared RMT method - idle level
inversion not supported") to keep the comment aligned with the guard.
wled00/bus_wrapper.h (1)

1375-1377: ⚠️ Potential issue | 🟡 Minor

Update the RMT-channel comment to match the actual guard.

The condition includes CONFIG_IDF_TARGET_ESP32C61 and CONFIG_IDF_TARGET_ESP32P4, but the comment only mentions C3/C5/C6.

✏️ Suggested fix
-      // On ESP32-C3/C5/C6 only the first 2 RMT channels are usable for transmitting
+      // On ESP32-C3/C5/C6/C61/P4 only the first 2 RMT channels are usable for transmitting
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/bus_wrapper.h` around lines 1375 - 1377, The inline comment above the
RMT-channel guard is outdated: the preprocessor condition in the if-statement
(the guard that checks CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5,
CONFIG_IDF_TARGET_ESP32C6, CONFIG_IDF_TARGET_ESP32C61, and
CONFIG_IDF_TARGET_ESP32P4) mentions only C3/C5/C6; update the comment near that
check (the block containing the if (num > 1) return I_NONE;) to accurately
reflect all targets in the condition (e.g., include C61 and P4 or generalize to
“ESP32-C3/C5/C6/C61/P4”) so the comment matches the guard.
🧹 Nitpick comments (3)
wled00/ota_update.cpp (1)

413-413: Replace raw chip-ID literals with named constants.

Line 413 introduces another hardcoded chip ID; using a named constant would make updates safer and reduce duplication with Line 440.

Refactor sketch
+constexpr uint16_t CHIP_ID_ESP32_C5 = 0x0017;
...
-  // 0x0017 = ESP32-C5
+  // CHIP_ID_ESP32_C5 = ESP32-C5
...
-    if (chipId != 0x0017) {
-      *bootloaderErrorMsg = "Chip ID mismatch - expected ESP32-C5 (0x0017), got 0x" + String(chipId, HEX);
+    if (chipId != CHIP_ID_ESP32_C5) {
+      *bootloaderErrorMsg = "Chip ID mismatch - expected ESP32-C5 (0x0017), got 0x" + String(chipId, HEX);
       return false;
     }

Based on learnings: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/ota_update.cpp` at line 413, Replace the hardcoded chip-ID literal
0x0017 with a named constant (e.g., CHIP_ID_ESP32_C5) and use that constant
wherever the literal appears (the occurrences around the current code in
ota_update.cpp, including the spot at line 413 and the duplicate at line 440).
Add the constant as a constexpr (uint16_t or appropriate type) alongside the
other chip ID constants in this file or header so it can be reused and avoid
duplication, then update any switch/case or comparison logic (functions handling
chip IDs) to reference CHIP_ID_ESP32_C5 instead of the raw 0x0017 literal.
wled00/improv.cpp (1)

13-16: Unresolved TODO: verify WiFi scan compatibility for C6, C61, and P4.

The in-line // ToDO check if C6, C61, P4 support this comment has not been acted on. If these targets share the same WiFi driver constraints as C5/C3/S2 (which all lack proper WiFi.scanNetworks() support at this IDF level), they should be added to the #if guard to avoid a silent no-op or crash when startImprovWifiScan() is called on those targets.

Do you want me to open a new issue to track the C6/C61/P4 WiFi scan verification, or generate a proposed fix assuming those targets should also disable scanning?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/improv.cpp` around lines 13 - 16, The preprocessor TODO indicates C6,
C61, and P4 targets may also lack WiFi.scanNetworks() support; update the guard
in improv.cpp to include those target macros (e.g., add
CONFIG_IDF_TARGET_ESP32C6 and CONFIG_IDF_TARGET_ESP32P4 / any vendor-provided
macro names that correspond to C6, C61, P4) so WLED_DISABLE_IMPROV_WIFISCAN is
defined for them too, and ensure startImprovWifiScan() will be disabled for
those builds; if you cannot confirm the exact macro names, open an issue to
track verification of C6/C61/P4 WiFi scan compatibility and reference improv.cpp
and the WLED_DISABLE_IMPROV_WIFISCAN symbol.
wled00/const.h (1)

70-71: Consider consolidating repeated target-condition groups.

The same C3/C5/C6/C61/P4 condition is repeated in multiple places, which increases future drift risk.

♻️ Proposed cleanup
+// Shared target bucket for reduced-channel ESP32 variants
+#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4)
+  `#define` WLED_TARGET_CLASS_LOW_CHANNEL 1
+#endif
...
-#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32P4)
+#if defined(WLED_TARGET_CLASS_LOW_CHANNEL)

Also applies to: 516-517, 529-530, 645-646

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/const.h` around lines 70 - 71, Create a named preprocessor macro to
consolidate the repeated target-condition group (e.g., define
IS_ESP32_C3_C5_C6_C61_P4 that expands to the existing disjunction of
CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5, CONFIG_IDF_TARGET_ESP32C6,
CONFIG_IDF_TARGET_ESP32C61, CONFIG_IDF_TARGET_ESP32P4) and then replace every
repeated condition occurrence (the ifdefs around the RMT/LEDC/I2S comments and
the other repeated checks at the locations flagged) with a single check using
that macro (e.g., `#if` defined(IS_ESP32_C3_C5_C6_C61_P4)); update any associated
comments to reference the new macro name for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@usermods/audioreactive/audio_reactive.cpp`:
- Around line 1800-1803: The conditional that wraps use of FPSTR(_analogmic) in
addToConfig (and equivalently in readFromConfig) omits CONFIG_IDF_TARGET_ESP32C6
so the code referencing the static _analogmic compiles on C6 where it isn't
declared; update the preprocessor guard to match the declaration's positive
guard by including CONFIG_IDF_TARGET_ESP32C6 in the excluded-target list (i.e.,
add !defined(CONFIG_IDF_TARGET_ESP32C6) to the `#if` check that surrounds the
amic/FPSTR(_analogmic) blocks in addToConfig and readFromConfig) so the
FPSTR(_analogmic) usage is compiled only when the static exists.
- Around line 2072-2074: The out-of-line definition for
AudioReactive::_analogmic uses a different preprocessor guard than its
declaration, causing a build error on ESP32-C6; update the definition's
conditional to exactly match the declaration's guard (the one using
CONFIG_IDF_TARGET_ESP32) so that AudioReactive::_analogmic is only defined when
it was declared (i.e., use the same `#if` defined(CONFIG_IDF_TARGET_ESP32)
condition as the declaration).

In `@wled00/fcn_declare.h`:
- Line 32: Fix the typo in the comment on the SOC_TOUCH_VERSION_2 preprocessor
line: change "fucntion" to "function" in the comment text associated with the
`#ifdef` SOC_TOUCH_VERSION_2 in fcn_declare.h so the comment reads "...have a
function to check touch state...".

---

Outside diff comments:
In `@wled00/bus_manager.cpp`:
- Around line 1160-1164: The code currently treats the single-I2S DMA case as
"first digital bus" by checking digitalCount == 1; change the non-parallel
branch to detect whether the current bus is the actual single-I2S DMA output
instead of relying on digitalCount. Replace the
(!PolyBus::isParallelI2S1Output() && digitalCount == 1) check with a call that
identifies the bus as the single-I2S output (for example use bus->isI2S1Output()
or an equivalent method/property that indicates this bus hosts the single I2S
DMA), so the condition becomes ((PolyBus::isParallelI2S1Output() && digitalCount
<= 8) || (!PolyBus::isParallelI2S1Output() && bus->isI2S1Output())) and adjust
any maxI2S accounting accordingly.

In `@wled00/FX_fcn.cpp`:
- Around line 1195-1200: The current usesI2S calculation assumes single-I2S is
bus 0 (using (!useParallelI2S && digitalCount == 1)), which undercounts maxI2S
for layouts where single-I2S is placed on a later bus; instead derive usesI2S
from the same bus-placement mapping used by allocation: replicate or call the
bus-placement logic to compute the index of the single-I2S bus for the target
when useParallelI2S is false (target-specific placement), then set usesI2S =
(useParallelI2S && digitalCount <= 8) || (!useParallelI2S && i2sBusIndex <
digitalCount), and ensure any maxI2S/memory calculations use that derived
i2sBusIndex rather than digitalCount == 1; update references to usesI2S,
useParallelI2S, digitalCount and maxI2S accordingly.

---

Duplicate comments:
In `@usermods/audioreactive/audio_reactive.cpp`:
- Around line 1163-1166: The conditional that skips calling
periph_module_reset(PERIPH_I2S0_MODULE) currently excludes
CONFIG_IDF_TARGET_ESP32C3 and CONFIG_IDF_TARGET_ESP32C5 but misses
CONFIG_IDF_TARGET_ESP32C6, so periph_module_reset will be invoked on ESP32-C6
where PERIPH_I2S0_MODULE is unavailable; update the preprocessor guard around
the delay(100) / periph_module_reset block to also check for
CONFIG_IDF_TARGET_ESP32C6 (i.e., add && !defined(CONFIG_IDF_TARGET_ESP32C6) to
the `#if`) so the reset call is skipped on C6 as well.
- Around line 1906-1915: appendConfigData currently conditionally prints mic
type options but omits CONFIG_IDF_TARGET_ESP32C6, causing unsupported "Generic
Analog" and "Generic I2S PDM" options to appear on C6 devices; update the three
preprocessor guards around uiScript.print calls that output
"addOption(dd,'Generic Analog',0);" and "addOption(dd,'Generic I2S PDM',5);"
(appearing near lines where appendConfigData emits those addOption entries and
again around the second block at ~1949-1953) to also check
!defined(CONFIG_IDF_TARGET_ESP32C6) so the guards become e.g. `#if`
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) &&
!defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6).
- Around line 1171-1182: The preprocessor guards omit ESP32C6 causing
PDM/ADC-over-I2S to be incorrectly enabled on C6; update the three conditionals
to include CONFIG_IDF_TARGET_ESP32C6: add !defined(CONFIG_IDF_TARGET_ESP32C6) to
the PDM auto-detect exclusion that checks i2sckPin/i2ssdPin/i2swsPin/dmType, add
|| defined(CONFIG_IDF_TARGET_ESP32C6) to the outer stub guard that wraps the
switch cases for dmType, and add || defined(CONFIG_IDF_TARGET_ESP32C6) to the
inner PDM stub guard so case 5 (PDM Microphone) is correctly excluded on C6.

In `@wled00/bus_manager.cpp`:
- Around line 1261-1263: The preprocessor guard that checks
CONFIG_IDF_TARGET_ESP32C61 is missing from the inline comment—update the comment
above the return in bus_manager.cpp (the line with `#if`
defined(...CONFIG_IDF_TARGET_ESP32C61...)) so it lists ESP32-C61 alongside
ESP32-C5/C6/P4 (e.g., "ESP32-C5/C6/C61/P4 use shared RMT method - idle level
inversion not supported") to keep the comment aligned with the guard.

In `@wled00/bus_wrapper.h`:
- Around line 1375-1377: The inline comment above the RMT-channel guard is
outdated: the preprocessor condition in the if-statement (the guard that checks
CONFIG_IDF_TARGET_ESP32C3, CONFIG_IDF_TARGET_ESP32C5, CONFIG_IDF_TARGET_ESP32C6,
CONFIG_IDF_TARGET_ESP32C61, and CONFIG_IDF_TARGET_ESP32P4) mentions only
C3/C5/C6; update the comment near that check (the block containing the if (num >
1) return I_NONE;) to accurately reflect all targets in the condition (e.g.,
include C61 and P4 or generalize to “ESP32-C3/C5/C6/C61/P4”) so the comment
matches the guard.

In `@wled00/ota_update.cpp`:
- Around line 18-19: The inline comment next to the BOOTLOADER_OFFSET definition
is stale; update the comment to reflect the preprocessor condition (`#if`
defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) ||
defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61)) by
explicitly listing esp32-S3, esp32-C3, esp32-C6 and esp32-C61 and removing the
"future support" wording for C6 so the comment accurately matches the condition
for BOOTLOADER_OFFSET.

In `@wled00/src/dependencies/dmx/SparkFunDMX.cpp`:
- Line 20: The preprocessor condition in SparkFunDMX.cpp still redundantly tests
!defined(ESP8266) and omits CONFIG_IDF_TARGET_ESP32P4; update the guard that
starts with `#if` !defined(ESP8266) && !defined(CONFIG_IDF_TARGET_ESP32C3)... to
remove the !defined(ESP8266) term and add && !defined(CONFIG_IDF_TARGET_ESP32P4)
so SparkFunDMX (SparkFunDMX.cpp) is excluded for the ESP32P4 target and avoids
compiling unnecessary dead code.

In `@wled00/xml.cpp`:
- Around line 322-329: Replace the magic literals "2, 6" with named constants to
clarify the C3 emulation intent and fix the comment typo; instead of hardcoded
values use the existing symbols (e.g., WLED_MAX_DIGITAL_CHANNELS and
WLED_MAX_ANALOG_CHANNELS or define WLED_EMULATED_C3_MAX_DIGITAL /
WLED_EMULATED_C3_MAX_ANALOG if clearer) in the conditional block that pretends
to be a C3 (the comment referencing isC3()); also correct the comment text from
"seetings_leds" to "settings_leds" so the purpose is clear and maintainable
while keeping WLED_MAX_BUTTONS unchanged.

---

Nitpick comments:
In `@wled00/const.h`:
- Around line 70-71: Create a named preprocessor macro to consolidate the
repeated target-condition group (e.g., define IS_ESP32_C3_C5_C6_C61_P4 that
expands to the existing disjunction of CONFIG_IDF_TARGET_ESP32C3,
CONFIG_IDF_TARGET_ESP32C5, CONFIG_IDF_TARGET_ESP32C6,
CONFIG_IDF_TARGET_ESP32C61, CONFIG_IDF_TARGET_ESP32P4) and then replace every
repeated condition occurrence (the ifdefs around the RMT/LEDC/I2S comments and
the other repeated checks at the locations flagged) with a single check using
that macro (e.g., `#if` defined(IS_ESP32_C3_C5_C6_C61_P4)); update any associated
comments to reference the new macro name for clarity.

In `@wled00/improv.cpp`:
- Around line 13-16: The preprocessor TODO indicates C6, C61, and P4 targets may
also lack WiFi.scanNetworks() support; update the guard in improv.cpp to include
those target macros (e.g., add CONFIG_IDF_TARGET_ESP32C6 and
CONFIG_IDF_TARGET_ESP32P4 / any vendor-provided macro names that correspond to
C6, C61, P4) so WLED_DISABLE_IMPROV_WIFISCAN is defined for them too, and ensure
startImprovWifiScan() will be disabled for those builds; if you cannot confirm
the exact macro names, open an issue to track verification of C6/C61/P4 WiFi
scan compatibility and reference improv.cpp and the WLED_DISABLE_IMPROV_WIFISCAN
symbol.

In `@wled00/ota_update.cpp`:
- Line 413: Replace the hardcoded chip-ID literal 0x0017 with a named constant
(e.g., CHIP_ID_ESP32_C5) and use that constant wherever the literal appears (the
occurrences around the current code in ota_update.cpp, including the spot at
line 413 and the duplicate at line 440). Add the constant as a constexpr
(uint16_t or appropriate type) alongside the other chip ID constants in this
file or header so it can be reused and avoid duplication, then update any
switch/case or comparison logic (functions handling chip IDs) to reference
CHIP_ID_ESP32_C5 instead of the raw 0x0017 literal.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9232bd4 and 491546b.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (30)
  • package.json
  • platformio.ini
  • usermods/audioreactive/audio_reactive.cpp
  • usermods/audioreactive/audio_source.h
  • wled00/FX.h
  • wled00/FX_fcn.cpp
  • wled00/FXparticleSystem.cpp
  • wled00/bus_manager.cpp
  • wled00/bus_wrapper.h
  • wled00/button.cpp
  • wled00/cfg.cpp
  • wled00/const.h
  • wled00/data/index.js
  • wled00/data/settings_wifi.htm
  • wled00/dmx_output.cpp
  • wled00/fcn_declare.h
  • wled00/improv.cpp
  • wled00/json.cpp
  • wled00/ota_update.cpp
  • wled00/pin_manager.cpp
  • wled00/set.cpp
  • wled00/src/dependencies/dmx/ESPDMX.cpp
  • wled00/src/dependencies/dmx/SparkFunDMX.cpp
  • wled00/udp.cpp
  • wled00/util.cpp
  • wled00/wled.cpp
  • wled00/wled.h
  • wled00/wled_boards.h
  • wled00/ws.cpp
  • wled00/xml.cpp
🚧 Files skipped from review as they are similar to previous changes (4)
  • wled00/data/index.js
  • wled00/FXparticleSystem.cpp
  • wled00/cfg.cpp
  • wled00/json.cpp

@softhack007
Copy link
Member

ToDo for P4:

esp_read_mac(mac, ESP_MAC_WIFI_STA);

--> E (27) system_api: 0 mac type is incorrect (not found)

possible solution

#include "esp_wifi_remote_api.h"
esp_err_t esp_wifi_remote_get_mac(wifi_interface_t ifx, uint8_t mac[6]);

see espressif/esp-idf#16251

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

keep This issue will never become stale/closed automatically magic major This is a non-trivial major feature and will take some time to implement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants