Skip to content

ESP-IDF V5#4838

Draft
netmindz wants to merge 61 commits intomainfrom
V5
Draft

ESP-IDF V5#4838
netmindz wants to merge 61 commits intomainfrom
V5

Conversation

@netmindz
Copy link
Member

@netmindz netmindz commented Aug 14, 2025

Update the code to handle at least being able to compile against V5


Edit (softhack007): espressif has "silently" changed a lot of APIs, and - in many cases - replacements are not behaving the same way as before. We are lucky that a few "legacy APIs" are still available, like the "V4" I2S driver. So even when "it compiles", there may be a lot more adaptations needed before "it really works".


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 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
  • "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

related

Summary by CodeRabbit

  • New Features

    • ESP32 builds updated for newer toolchains, improving PWM/RMT handling and compatibility.
  • Bug Fixes

    • Improved network handling and IP reporting across UI, discovery, and services.
    • Ethernet initialization and static IP selection logic corrected.
    • DMX input/RDM handling improved for reliability.
    • SHA‑1 compatibility shim added for newer ESP32 toolchains.
  • Chores

    • Build tooling and dependency versions refreshed for current toolchains.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 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.

  • 🔍 Trigger a full review

Walkthrough

Refactors build and platform compatibility for ESP32/ESP-IDF v5: gates NeoEsp32RmtHI compilation by WLED_USE_SHARED_RMT, renames Network → WLEDNetwork across the codebase, updates LEDC/ETH/UDP/MDNS/NTP APIs for IDF v5, adds SHA-1 shim, DMX RDM personality changes, and updates platformio/requirements.

Changes

Cohort / File(s) Summary
NeoEsp32RmtHI guard
lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h, lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp, lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S
Wrapped RMT driver headers/source/ASM with #if !defined(WLED_USE_SHARED_RMT) to exclude when shared RMT is used.
Network core rename
wled00/src/dependencies/network/Network.h, wled00/src/dependencies/network/Network.cpp
Renamed NetworkClassWLEDNetworkClass and global NetworkWLEDNetwork; adjusted localMAC handling for ESP32 Ethernet.
Network API propagation
wled00/*, wled00/src/dependencies/e131/ESPAsyncE131.cpp, wled00/src/dependencies/espalexa/Espalexa.h, usermods/*, lib/*, wled00/src/dependencies/network/*
Replaced Network.* references with WLEDNetwork.* across many modules (json, udp, improv, e131, espalexa, usermods, wled.cpp/h, xml, bus_manager, etc.) and updated WLED_CONNECTED macro.
Build/Platform manifest
platformio.ini, requirements.txt
Added ESP-IDF v5 manifest/envs, introduced -D WLED_USE_SHARED_RMT and other build flags, updated library versions and Python/dev deps.
LEDC / PWM modernization
wled00/bus_manager.cpp, usermods/PWM_fan/PWM_fan.cpp
Conditionalized LEDC API for ESP-IDF ≥5: switch ledcSetup/ledcAttachPinledcAttach and ledcDetachPinledcDetach; changed semaphore type to SemaphoreHandle_t.
DMX / RDM updates
wled00/dmx_input.h, wled00/dmx_input.cpp
RDM callbacks changed to receive separate request/response headers; added personalities array and createPersonalities(), switched driver install to use personalities count, added null checks and DMX_CONFIG_DEFAULT usage.
SHA-1 shim
wled00/mbedtls_sha1_shim.cpp, wled00/fcn_declare.h, wled00/util.cpp
Added mbedtls SHA-1 wrappers mapping to Arduino SHA1Builder for ESP32 (IDF ≥5.2.0); guarded computeSHA1/getDeviceId/device fingerprint code for IDF v5+.
Ethernet / ETH API changes
wled00/network.cpp
Reordered ETH.begin() parameters to match updated API (PHY type first, then address, mdc/mdio, power, clock mode) and minor formatting fixes.
NeoPixelBus / bus wrapper shim
wled00/bus_wrapper.h
Added macro remapping for NeoPixelBus RMT/I2S method names on ESP32 and defined new 32-bit host pin constants for ESP32.
NTP / UDP flush handling
wled00/ntp.cpp, wled00/src/dependencies/espalexa/Espalexa.h
Use clear() instead of flush() on ESP-IDF ≥5 where appropriate; adjusted UDP handling and multicast IP sourcing to use WLEDNetwork.localIP().
Misc. API/type modernizations & constants
wled00/const.h, wled00/bus_manager.cpp, wled00/wled.h
Converted macro to constexpr for WLED_MAX_ANALOG_CHANNELS; replaced xSemaphoreHandle with SemaphoreHandle_t; updated WLED_CONNECTED to use WLEDNetwork.isConnected().

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • willmmiles
  • netmindz
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.33% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ESP-IDF V5' directly corresponds to the PR's primary objective of updating the codebase to compile against ESP-IDF v5 while preserving v4 compatibility.

✏️ 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

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.

@netmindz netmindz changed the title V5 ESP-IDF V5 Aug 14, 2025
@netmindz netmindz mentioned this pull request Aug 15, 2025
@netmindz netmindz requested a review from willmmiles August 16, 2025 11:30
@netmindz
Copy link
Member Author

I'm not sure if renaming Network is the right approach to fix the conflict @willmmiles

@netmindz
Copy link
Member Author

I am also unsure why we are seeing linker errors for things like mbedtls_sha1_starts

@netmindz netmindz added this to the 0.17.0 milestone Aug 16, 2025
@willmmiles
Copy link
Member

I'm not sure if renaming Network is the right approach to fix the conflict @willmmiles

Hm, it looks like it's just a bag of stateless utility functions. Probably it should be a namespace instead of a class. I don't think there's a practical solution to avoid the collision other than renaming, unless the newer core offers these utilities itself. (In fact I'd also suggest pulling them in to wled00/network.cpp , given the use of WLED-specific #defines.)

(Best pratice would've been that the upstream libraries put everything they do in a namespace, eg. Arduino::Network or somesuch, but here we are.)

I am also unsure why we are seeing linker errors for things like mbedtls_sha1_starts

I believe that the Tasmota platform omits mbedtls to save flash space, as they've gone over to BearSSL. Looks like they're still exposing the headers though - I don't know if that's an IDF bug or something wrong with their build process.

AsyncWebServer needs an SHA1 implementation as it is required for WebSockets. It looks like the upstream AWS folks have switched over to IDFv5 functions and vendored in Espressif's implementation when building on IDFv4. I'll see if I can pull those patches.

@sombree
Copy link

sombree commented Aug 25, 2025

With few fixes it builds.
image

MQTT
With the change below I was able to build it (I don’t have a way to test runtime behavior):
In AsyncMqttClient.hpp line 41, change:
#if ESP32
to
#ifdef ESP32

mbedTLS
Upstream ESPAsyncWebServer made the change here: 57244d47444a3281ba30f4c9da60fb23d05eb495
Applying similar changes to Aircoookie/ESPAsyncWebServer.git#v2.4.2 made it buildable.

WiFi
I had crash related to memcpy and MAC adress was shown as 000000000000. Quick fixes are below.

wled.cpp

Compare IPAddress to a value, not to 0 (prevents pointer overload → memcmp on nullptr) and clamp index (prevents out-of-range access cascading into bad compares).

@@ void WLED::initConnection()
-  if (multiWiFi[selectedWiFi].staticIP != 0U && multiWiFi[selectedWiFi].staticGW != 0U) {
-    WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress);
-  } else {
-    WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0));
-  }
+ if (multiWiFi.empty()) {                       // guard: handle empty WiFi list safely
+  WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0));
+ } else {
+  if (selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // guard: ensure valid index
+  if (multiWiFi[selectedWiFi].staticIP != IPAddress((uint32_t)0) &&
+    multiWiFi[selectedWiFi].staticGW != IPAddress((uint32_t)0)) { // guard: compare as IPAddress to avoid pointer overload
+    WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress);
+  } else {
+    WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0));
+  }
+ }

ESP32 MAC fallback (fix Info tab showing 000000000000)

@@ (top of file)
+#ifdef ARDUINO_ARCH_ESP32
+#include <esp_mac.h>  // fallback MAC read from efuse
+#endif
@@ // generate module IDs must be done before AP setup
-escapedMac = WiFi.macAddress();
+escapedMac = WiFi.macAddress();
+#ifdef ARDUINO_ARCH_ESP32
+if (escapedMac == "00:00:00:00:00:00") { // fix: fallback to efuse MAC if WiFi not started
+  uint8_t m[6] = {0};
+  if (esp_read_mac(m, ESP_MAC_WIFI_STA) == ESP_OK) {
+    char buf[18];
+    sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
+    escapedMac = buf;
+  }
+}
+#endif
 escapedMac.replace(":", "");
 escapedMac.toLowerCase();

network.cpp

  1. Guard empty Wi-Fi list before accessing multiWiFi[0]
@@ int findWiFi(...)
-  if (multiWiFi.size() <= 1) {
-    DEBUG_PRINTF_P(PSTR("WiFi: Defaulf SSID (%s) used.\n"), multiWiFi[0].clientSSID);
-    return 0;
-  }
+  if (multiWiFi.size() <= 1) {
+    if (multiWiFi.empty()) return 0; // guard: handle empty list safely
+    DEBUG_PRINTF_P(PSTR("WiFi: Defaulf SSID (%s) used.\n"), multiWiFi[0].clientSSID);
+    return 0;
+  }
  1. Safe BSSID compare (both sides must exist & configured BSSID non-zero)
@@ for (size_t n = 0; n < multiWiFi.size(); n++)
-    bool foundBSSID = memcmp(multiWiFi[n].bssid, WiFi.BSSID(o), 6) == 0;
+    const uint8_t* _scanBSSID = WiFi.BSSID(o);
+    bool _cfgHasBSSID = false; for (int _i = 0; _i < 6; _i++) _cfgHasBSSID |= multiWiFi[n].bssid[_i];
+    bool foundBSSID = (_scanBSSID && _cfgHasBSSID) && memcmp(multiWiFi[n].bssid, _scanBSSID, 6) == 0; // guard: safe memcmp against nullptr/empty BSSID

Usermods
I had more issues with usermods—the new toolchain’s linker was GC’ing/orphaning the old section-based registration. I switched registration to a ctor-based dynamic hook (no new sections) and kept legacy dtors for backward compatibility.
I used the RF433 usermod as the example.

Modified um_manager.cpp:

#include "wled.h"
#include <assert.h>

/*
 * Registration and management utility for v2 usermods
 *
 * Discovery paths, in this order:
 *  1) Legacy dtors window: .dtors.tbl.usermods.0 ... .99 (older toolchains)
 *  2) Dynamic fallback: usermods call registerUsermod(Usermod*) from a ctor
 */

// -------- Legacy dtors window (keep for backward compatibility) --------
static Usermod * const _usermod_table_begin[0]
  __attribute__((section(".dtors.tbl.usermods.0"), unused)) = {};
static Usermod * const _usermod_table_end[0]
  __attribute__((section(".dtors.tbl.usermods.99"), unused)) = {};

struct UMSpan {
  Usermod* const* begin;
  Usermod* const* end;
};

static inline UMSpan reg_dtors_span() {
  UMSpan s{_usermod_table_begin, _usermod_table_end};
  return s;
}

// ----- Dynamic fallback: usermods can push themselves here at boot -----
static Usermod* g_dynMods[16];
static size_t   g_dynCnt = 0;

// Weak, so a stronger definition elsewhere (if any) wins.
// Usermods may call this from a constructor to guarantee registration.
extern "C" void registerUsermod(Usermod* m) __attribute__((weak));
extern "C" void registerUsermod(Usermod* m) {
  if (m && g_dynCnt < (sizeof(g_dynMods)/sizeof(g_dynMods[0]))) {
    g_dynMods[g_dynCnt++] = m;
  }
}

// ----- Common iteration helpers -----

// Accept any callable (incl. capturing lambdas/functors)
template<typename Fn>
static inline void forEachMod(Fn&& fn) {
  // 1) legacy dtors table
  {
    UMSpan s = reg_dtors_span();
    for (auto p = s.begin; p < s.end; ++p) {
      Usermod* m = *p;
      if (m) fn(m);
    }
  }
  // 2) dynamic list
  for (size_t i = 0; i < g_dynCnt; ++i) {
    if (g_dynMods[i]) fn(g_dynMods[i]);
  }
}

static inline size_t countMods() {
  size_t count = 0;
  // dtors window
  {
    UMSpan s = reg_dtors_span();
    count += (size_t)(s.end - s.begin);
  }
  // dynamic
  count += g_dynCnt;
  return count;
}

// --------- Usermod Manager methods (iterate via forEachMod) ---------

void UsermodManager::setup()             { forEachMod([](Usermod* m){ m->setup(); }); }
void UsermodManager::connected()         { forEachMod([](Usermod* m){ m->connected(); }); }
void UsermodManager::loop()              { forEachMod([](Usermod* m){ m->loop(); }); }
void UsermodManager::handleOverlayDraw() { forEachMod([](Usermod* m){ m->handleOverlayDraw(); }); }

void UsermodManager::appendConfigData(Print& dest) {
  forEachMod([&](Usermod* m){ m->appendConfigData(dest); });
}

bool UsermodManager::handleButton(uint8_t b) {
  bool overrideIO = false;
  forEachMod([&](Usermod* m){
    if (m->handleButton(b)) overrideIO = true;
  });
  return overrideIO;
}

bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) {
  bool got = false;
  forEachMod([&](Usermod* m){
    if (got) return;
    if (mod_id > 0 && m->getId() != mod_id) return;
    if (m->getUMData(data)) got = true;
  });
  return got;
}

void UsermodManager::addToJsonState(JsonObject& obj) {
  forEachMod([&](Usermod* m){ m->addToJsonState(obj); });
}

void UsermodManager::addToJsonInfo(JsonObject& obj) {
  auto um_id_list = obj.createNestedArray("um");
  forEachMod([&](Usermod* m){
    um_id_list.add(m->getId());
    m->addToJsonInfo(obj);
  });
}

void UsermodManager::readFromJsonState(JsonObject& obj) {
  forEachMod([&](Usermod* m){ m->readFromJsonState(obj); });
}

void UsermodManager::addToConfig(JsonObject& obj) {
  forEachMod([&](Usermod* m){ m->addToConfig(obj); });
}

bool UsermodManager::readFromConfig(JsonObject& obj) {
  bool allComplete = true;
  forEachMod([&](Usermod* m){
    if (!m->readFromConfig(obj)) allComplete = false;
  });
  return allComplete;
}

#ifndef WLED_DISABLE_MQTT
void UsermodManager::onMqttConnect(bool sessionPresent) {
  forEachMod([&](Usermod* m){ m->onMqttConnect(sessionPresent); });
}

bool UsermodManager::onMqttMessage(char* topic, char* payload) {
  bool handled = false;
  forEachMod([&](Usermod* m){
    if (!handled && m->onMqttMessage(topic, payload)) handled = true;
  });
  return handled;
}
#endif // WLED_DISABLE_MQTT

#ifndef WLED_DISABLE_ESPNOW
bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) {
  bool handled = false;
  forEachMod([&](Usermod* m){
    if (!handled && m->onEspNowMessage(sender, payload, len)) handled = true;
  });
  return handled;
}
#endif // WLED_DISABLE_ESPNOW

void UsermodManager::onUpdateBegin(bool init) {
  forEachMod([&](Usermod* m){ m->onUpdateBegin(init); });
}

void UsermodManager::onStateChange(uint8_t mode) {
  forEachMod([&](Usermod* m){ m->onStateChange(mode); });
}

Usermod* UsermodManager::lookup(uint16_t mod_id) {
  Usermod* found = nullptr;
  forEachMod([&](Usermod* m){
    if (!found && m->getId() == mod_id) found = m;
  });
  return found;
}

size_t UsermodManager::getModCount() {
  return countMods();
}

/* Usermod v2 interface shim for oappend */
Print* Usermod::oappend_shim = nullptr;
void Usermod::appendConfigData(Print& settingsScript) {
  assert(!oappend_shim);
  oappend_shim = &settingsScript;
  this->appendConfigData();
  oappend_shim = nullptr;
}

At the end of usermod_v2_RF433.cpp I added:

// --- Registration via dynamic fallback (no custom sections) ---
static RF433Usermod usermod_v2_RF433;
REGISTER_USERMOD(usermod_v2_RF433);   // OK to keep for legacy dtors builds

extern "C" void registerUsermod(Usermod*) __attribute__((weak));

__attribute__((constructor, used))
static void __rf433_ctor_register(void) {
  if (registerUsermod) registerUsermod(&usermod_v2_RF433);
}

NeoPixelBus
I also had issues with NeoPixelBus. At boot, IDF runs check_rmt_legacy_driver_conflict() and aborts if both the old (legacy) RMT driver and the new (“driver_ng” / v2) RMT driver are linked into firmware.
I switched to Makuna/NeoPixelBus.git#CORE3 and made a small change:

--- a/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h
+++ b/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h
@@ -1,5 +1,7 @@
 #pragma once
+// Needed for ESP_* macros that take a log_tag
+#include "esp_log.h"
+static const char* TAG = "NeoEsp32RmtX";

And I added a temporary shim in wled00/bus_wrapper.h. Since ESP-IDF 5 switched to the new RMT “driver_v2,” Makuna renamed all of the “N” (legacy/driver_v1) variants to “X” (v2) under internal/methods/ESP/ESP32/*

// --- temporary shim for NeoPixelBus CORE3 / RMT driver_v2 ------------------
#if __has_include(<NeoPixelBus.h>)
  #define NeoEsp32RmtNWs2812xMethod  NeoEsp32RmtXWs2812xMethod
  #define NeoEsp32RmtNSk6812Method   NeoEsp32RmtXSk6812Method
  #define NeoEsp32RmtN400KbpsMethod  NeoEsp32RmtX400KbpsMethod
  #define NeoEsp32RmtNTm1814Method   NeoEsp32RmtXTm1814Method
  #define NeoEsp32RmtNTm1829Method   NeoEsp32RmtXTm1829Method
  #define NeoEsp32RmtNTm1914Method   NeoEsp32RmtXTm1914Method
  #define NeoEsp32RmtNApa106Method   NeoEsp32RmtXApa106Method
  #define NeoEsp32RmtNWs2805Method   NeoEsp32RmtXWs2805Method
#endif
// ---------------------------------------------------------------------------

@netmindz
Copy link
Member Author

Thanks for helping with this @sombree

Could you please open a PR against the V5 branch and we can then pull in your fixes that way, maintaining attribution for your work

sombree added a commit to sombree/WLED that referenced this pull request Sep 29, 2025
…(ESP-IDF 5.3.4 / arduino-esp32 v3.1.4).

Based on wled#4838.
sombree added a commit to sombree/WLED that referenced this pull request Sep 29, 2025
…(ESP-IDF 5.3.4 / arduino-esp32 v3.1.4).

Based on wled#4838.
softhack007 and others added 7 commits December 1, 2025 20:26
Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
in V5, LEDC_CHANNEL_MAX and LEDC_SPEED_MODE_MAX are enum constants, and the compiler does not allow a macro where enums are implicitly treated as int.
Solution: change into constexpr with static type cast => still computed by the compiler and does not create any local variable.
…ib_ignore

* esp32_idf_V5 has the main build_unflags and lib_ignore
* next level (esp32, esp32s3, esp32s2, esp32c3) inherits from esp32_idf_V5
* user buildenvs _only_ inherit from (esp32, esp32s3, esp32s2, esp32c3)
{
EA_DEBUGLN("# Responding to description.xml ... #\n");
IPAddress localIP = Network.localIP();
IPAddress localIP = WLEDNetwork.localIP();
Copy link
Member Author

Choose a reason for hiding this comment

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

Should we revert this in favor of using a #define @willmmiles ?

netmindz and others added 8 commits February 7, 2026 19:28
plus
- re-enabled one S3 and one S2 build
- disabled c++20 deprecation warnings
- minor indentation fix
… udp.flush()

* add esp32dev_V4 for regression checking w.r.t. V4 framework
* bring back lost V4 code
* udp.flush() is deprecated --> udp.clear()
* disable "temporary shim for NeoPixelBus CORE3" for V4
* better way to prevent compiling NeoEsp32RmtHIMethod
@softhack007
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@softhack007
Copy link
Member

softhack007 commented Feb 8, 2026

@coderabbitai take a look at the various migration guides (see #4838 (comment)). Then scan the complete source code in this PR brach for remaining hidden incompatibilities with esp-idf V5.3.x or arduino-esp32 v3.3.x.
Our goal is to use the same codebase for V4 (esp-idf 4.4.6, arduino-esp32 v 2.0.14) and V5 (esp-idf 5.x, arduino-esp32 v 3.x) builds. Provide a summary of your findings (if any).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Scan for potential V5 incompatibilities across the codebase

echo "=== 1. Checking for deprecated ESP-IDF APIs ==="
# Timer API changes (V5 deprecated old timer API)
rg "timer_group_t|timer_idx_t|timer_config_t|timer_init|timer_set_" --type cpp -n | head -20

echo ""
echo "=== 2. Checking for GPIO API changes ==="
# V5 changed some GPIO APIs
rg "gpio_pad_select_gpio|rtc_gpio_" --type cpp -n | head -20

echo ""
echo "=== 3. Checking for SPI API changes ==="
# V5 changed SPI host configuration
rg "spi_bus_config_t|spi_device_interface_config_t|SPI_HOST|HSPI_HOST|VSPI_HOST" --type cpp -n | head -20

echo ""
echo "=== 4. Checking for UART API changes ==="
rg "uart_config_t|uart_driver_install|uart_param_config" --type cpp -n | head -20

echo ""
echo "=== 5. Checking for ADC/DAC API usage ==="
# Already flagged but check for more instances
rg "adc_power_|dac_output_|adc1_config|adc_set_" --type cpp -n | head -20

echo ""
echo "=== 6. Checking for TWAI (CAN) API changes ==="
rg "can_driver_install|can_transmit|can_receive|CAN_" --type cpp -n | head -20

echo ""
echo "=== 7. Checking for esp_wifi API changes ==="
rg "esp_wifi_set_protocol|esp_wifi_set_bandwidth|WIFI_PROTOCOL_" --type cpp -n | head -20

echo ""
echo "=== 8. Checking for FreeRTOS API changes ==="
# V5 updated FreeRTOS version
rg "xQueueHandle|xSemaphoreHandle|xTaskHandle|portTICK_RATE_MS" --type cpp -n | head -20

echo ""
echo "=== 9. Checking for deprecated heap functions ==="
rg "heap_caps_get_free_size|heap_caps_get_largest_free_block" --type cpp -n | head -20

echo ""
echo "=== 10. Checking for NVS API changes ==="
rg "nvs_flash_init|nvs_open|nvs_set_|nvs_get_|nvs_commit" --type cpp -n | head -20

Length of output: 4957


🏁 Script executed:

#!/bin/bash
# Check for Arduino-ESP32 v3 specific incompatibilities

echo "=== 1. Checking for removed WiFi APIs ==="
rg "WiFi\.macAddress\(\)|WiFi\.BSSID\(\)" --type cpp -n | head -20

echo ""
echo "=== 2. Checking for Ethernet API changes ==="
# ETH.begin signature changed (already fixed but check for other ETH APIs)
rg "ETH\.(config|setHostname|setDNS|enableIPv6)" --type cpp -n | head -20

echo ""
echo "=== 3. Checking for removed/changed SPIClass methods ==="
rg "SPI\.setFrequency|SPI\.setDataMode|SPI\.setBitOrder" --type cpp -n | head -20

echo ""
echo "=== 4. Checking for Serial API changes ==="
rg "Serial\.setDebugOutput|HardwareSerial" --type cpp -n | head -20

echo ""
echo "=== 5. Checking for deprecated preferences API ==="
rg "preferences\.begin|preferences\.putBytes|preferences\.getBytes" --type cpp -n | head -20

echo ""
echo "=== 6. Checking for Wire (I2C) API changes ==="
rg "Wire\.begin|Wire\.setClock|Wire\.setTimeOut" --type cpp -n | head -20

echo ""
echo "=== 7. Checking for WebServer API changes ==="
rg "WebServer\.|AsyncWebServer\." --type cpp -n | head -30

echo ""
echo "=== 8. Checking for Update/OTA API changes ==="
rg "Update\.begin|Update\.write|Update\.end" --type cpp -n | head -20

Length of output: 4124


🏁 Script executed:

#!/bin/bash
# Check for missing ESP-IDF version guards in critical areas

echo "=== Checking files with hardware API calls but no ESP_IDF_VERSION guards ==="

# Find files with LEDC API
echo "Files using LEDC APIs:"
rg -l "ledcAttach|ledcWrite|ledcSetup" --type cpp | while read file; do
  if ! grep -q "ESP_IDF_VERSION" "$file"; then
    echo "  ⚠️  $file - No ESP_IDF_VERSION guard found"
  else
    echo "  ✓  $file - Has version guards"
  fi
done

echo ""
# Find files with I2S API
echo "Files using I2S APIs:"
rg -l "i2s_driver_install|i2s_set_pin|i2s_start|i2s_write" --type cpp | while read file; do
  if ! grep -q "ESP_IDF_VERSION" "$file"; then
    echo "  ⚠️  $file - No ESP_IDF_VERSION guard found"
  else
    echo "  ✓  $file - Has version guards"
  fi
done

echo ""
# Find files with RMT API (if any direct usage)
echo "Files using RMT APIs:"
rg -l "rmt_config|rmt_driver_install|rmt_write" --type cpp | while read file; do
  if ! grep -q "ESP_IDF_VERSION" "$file"; then
    echo "  ⚠️  $file - No ESP_IDF_VERSION guard found"
  else
    echo "  ✓  $file - Has version guards"
  fi
done

Length of output: 476


🏁 Script executed:

#!/bin/bash
# Check for potential issues in specific critical files

echo "=== Detailed check of util.cpp (has known issues) ==="
cat wled00/util.cpp | grep -A 5 -B 5 "esp_chip_info\|esp_efuse_mac\|esp_read_mac"

echo ""
echo "=== Check bus_manager.cpp for additional hardware APIs ==="
cat wled00/bus_manager.cpp | grep -n "SemaphoreHandle_t\|xSemaphore\|ledcAttach\|ledcDetach"

echo ""
echo "=== Check dmx_input.cpp for DMX driver compatibility ==="
cat wled00/dmx_input.cpp | head -50 | grep -E "dmx_|rdm_|ESP_IDF"

echo ""
echo "=== Check for any remaining xSemaphoreHandle usage ==="
rg "xSemaphoreHandle|xQueueHandle|xTaskHandle" --type cpp -n

Length of output: 1670


🌐 Web query:

ESP-IDF 5.3 migration guide breaking changes API

💡 Result:

Key ESP-IDF v5.3 migration (from v5.2 → v5.3) API / breaking-change items called out in Espressif’s migration guide:

  • Bluetooth (Bluedroid): esp_bt_dev_set_device_name() / esp_bt_dev_get_device_name() are deprecated; use esp_bt_gap_set_device_name() / esp_bt_gap_get_device_name() (or BLE GAP equivalents). [1]
  • VFS UART device APIs renamed / deprecated: all esp_vfs_dev_uart_* APIs are deprecated and replaced by uart_vfs_dev_* APIs in uart_vfs.h (e.g., esp_vfs_dev_uart_registeruart_vfs_dev_register). [2]
  • Sleep / Power management: esp_sleep_enable_ext1_wakeup_with_level_mask() is deprecated; use esp_sleep_enable_ext1_wakeup_io() / esp_sleep_disable_ext1_wakeup_io(). [3]
  • Peripherals / drivers packaging: the monolithic driver component is split into smaller esp_driver_* components; if you used linker.lf mappings that referenced libdriver.a, you may need to update them (e.g., libesp_driver_gpio.a). [4]
  • I2S callback event struct: in i2s_event_data_t, the data field is deprecated; use dma_buf instead. [4]
  • Toolchain header behavior: including <sys/dirent.h> no longer provides prototypes like opendir(); include <dirent.h> explicitly. [5]
  • ESP HTTPS OTA behavior change: when esp_https_ota_config_t::bulk_flash_erase = true and image length is known from HTTP headers, erase size is adjusted to the image length (not “erase whole flash”). [6]
  • Partition table generation: app partition sizes must be 4KB-aligned (generator errors out otherwise). [3]
  • Flash encryption behavior/config: new default CONFIG_SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART encrypts only the app image length (not the full app partition) to reduce first-boot encryption time. [7]

Other v5.3 release-note breaking API changes you may also need to handle (depending on which 5.3.x you upgrade to):

  • ESP-NOW send callback signature change: callback parameter changed from mac_addr to esp_now_send_info_t. [8]
  • MbedTLS hostname requirement: for server cert verification with MbedTLS, you must call mbedtls_ssl_set_hostname() before the connection begins (no change if you use esp-tls). [8]

Sources: ESP-IDF v5.3 migration guide pages and ESP-IDF GitHub release notes. [1][2][3][4][5][6][7][8]


🌐 Web query:

Arduino-ESP32 3.3 migration guide breaking changes from 2.0

💡 Result:

There isn’t a separate “2.0 → 3.3” migration guide; Espressif’s documented breaking changes are covered in the “Migration from 2.x to 3.0” guide (and that’s the main jump you must handle), then you should skim 3.1/3.2/3.3 release notes for any additional changes. [1], [2]

Breaking changes you’ll hit when moving from Arduino-ESP32 2.0.x → 3.x (incl. 3.3.x)

From the official 2.x → 3.0 migration guide: [1]

  • Core/IDF base change: 2.x is based on ESP-IDF 4.4, 3.x is based on ESP-IDF 5.x, so many peripheral drivers/APIs were refactored. [1]
  • Build flags: if you use custom “extra flags”, you may now override required defaults—ensure -MMD -c are present in C/C++ extra flags. [1]
  • ADC: removed APIs: analogSetClockDiv, adcAttachPin, analogSetVRefPin. [1]
  • Hall sensor: no longer supported; hallRead removed. [1]
  • BLE API changes: several APIs switch between std::string and Arduino String; UUID type changes to BLEUUID; some scan APIs change return types (e.g., results pointer). [1]
  • I2S: driver/API redesigned to match the newer ESP-IDF driver model. [1]
  • LEDC (PWM): major API change—channels are effectively managed differently (auto-assigned to pins); removed ledcSetup and ledcAttachPin, replaced by newer attach-style APIs (e.g., ledcAttach), and several functions change parameters from “channel” to “pin”. [1]
  • RMT: API reworked (many functions change signatures to use int pin, async/blocking semantics updated, some functions renamed/removed). [1]
  • Timers: timer API simplified/refactored; many older config/alarm functions removed and replaced with newer patterns (e.g., combined alarm setup). [1]
  • HardwareSerial (UART): some configuration APIs change parameter types from uint8_t to typed enums (e.g., SerialMode, SerialHwFlowCtrl). [1]

What’s “3.3-specific” vs “3.0 breakage”?

Arduino-ESP32 3.3.0 is a minor line update based on ESP-IDF 5.5.x (roadmap lists 3.3.0 = 2025-08-06, ESP-IDF 5.5), and the GitHub release notes for 3.3.x largely read as features/fixes rather than a new wave of “2.x-style” breaking API removals. [3], [2]

Practical guidance: do the migration using the 2.x → 3.0 guide first (that’s where the real breaking changes are), then build/test on your target 3.3.x and review the 3.3.x release notes for anything affecting the subsystems you use (Wi‑Fi/TLS, USB/TinyUSB, UART, LEDC, etc.). [1], [2]

Sources: [1] Migration guide 2.x→3.0, [2] arduino-esp32 GitHub releases (3.3.x notes), [3] arduino-esp32 release roadmap (3.3.0 date/IDF base).


@softhack007: I've completed a comprehensive scan of the codebase for ESP-IDF V5.3.x and Arduino-ESP32 v3.3.x incompatibilities. Here's my detailed analysis:

🔴 Critical Issues Requiring Immediate Attention

1. util.cpp - Chip Identification APIs (Lines 1165-1179)

Status: ⚠️ BROKEN in V5 builds

// Lines 1165-1167: Missing includes and unguarded APIs
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
esp_efuse_mac_get_default((uint8_t*)fp);

Problem: These ESP-IDF APIs require proper headers that may not be included.
Fix needed:

`#ifdef` ESP32
  `#include` <esp_chip_info.h>  // Add this
  `#include` <esp_efuse.h>      // Add this
  `#if` ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
    `#include` <esp_mac.h>      // V5 requirement
  `#endif`
`#endif`

2. deep_sleep Usermod - RTC GPIO APIs (deep_sleep.cpp:214-238)

Status: ⚠️ Needs V5 guards

Multiple rtc_gpio_*() calls without ESP-IDF version protection:

  • rtc_gpio_hold_dis()
  • rtc_gpio_init()
  • rtc_gpio_set_direction()
  • rtc_gpio_pullup_dis() / rtc_gpio_pulldown_dis()
  • rtc_gpio_hold_en()

Recommendation: Add conditional compilation:

`#if` ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
  // V5 RTC GPIO API (likely unchanged, but verify)
  rtc_gpio_hold_dis((gpio_num_t)wakeupPin);
  // ... rest of calls
`#else`
  // V4 API (current code)
`#endif`

🟡 Moderate Issues - May Cause Warnings/Deprecation

3. Heap Monitoring Functions (wled.cpp:275-291, fcn_declare.h:492-493)

Status: ⚠️ Deprecated but still functional

heap_caps_get_free_size()          // Deprecated in IDF 5.x
heap_caps_get_largest_free_block()  // Deprecated in IDF 5.x

ESP-IDF V5.3 Recommendation: These still work but may emit deprecation warnings. Consider future migration to:

  • heap_caps_get_info() (returns struct with all heap stats)
  • Or accept the warnings for now (no runtime impact)

4. pwm_outputs Usermod - Missing LEDC Guards

Status: ⚠️ Will fail on V5 without guards

File: usermods/pwm_outputs/pwm_outputs.cpp

This usermod uses old LEDC APIs (ledcSetup, ledcAttachPin) without version guards like PWM_fan does.

Fix: Apply the same pattern as PWM_fan.cpp:

`#if` ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
  ledcAttach(pin, freq, resolution);
`#else`
  ledcSetup(channel, freq, resolution);
  ledcAttachPin(pin, channel);
`#endif`

5. ADC Deprecated Constant (util.cpp:1177, audioreactive)

Status: ⚠️ Generates compile warnings

// Line 1177:
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ...);
// audioreactive/audio_source.h:625:
adc1_config_channel_atten(adc1_channel_t(channel), ADC_ATTEN_DB_11);

Fix: Replace with:

ADC_ATTEN_DB_11 → ADC_ATTEN_DB_12  // Same behavior, new name

🟢 Minor/Informational Issues

6. WiFi.macAddress() Usage (3 occurrences)

Status:Compatible but has fallback

Files: wled.cpp:469, Espalexa.h:130, 339

Arduino-ESP32 v3 changed behavior slightly, but the API signature is preserved. The existing fallback code in wled.cpp (lines 470-481) using esp_read_mac() handles edge cases well.

7. Serial.setDebugOutput() (wled.cpp:386)

Status:Compatible

This API is preserved in Arduino-ESP32 v3.x with the same signature.

8. NeoESP32RmtHI Library

Status:Intentionally disabled

Missing ESP_IDF_VERSION guards in NeoEsp32RmtHIMethod.h, but this library is:

  • Wrapped in #if false (effectively disabled)
  • Listed in lib_ignore for V5 builds
  • Replaced by NeoPixelBus CORE3 with RMT driver_v2

No action needed.


📋 ESP-IDF 5.3 Specific Changes Not Found in Codebase

Good news - WLED doesn't appear to use these deprecated V5.3 APIs:

Bluetooth GAP: No esp_bt_dev_set_device_name() usage (not applicable)
VFS UART: No direct esp_vfs_dev_uart_* calls (using Arduino wrappers)
EXT1 wakeup: deep_sleep uses EXT0 style APIs
ESP-NOW: Not using the send callback that changed signature
MbedTLS hostname: AsyncWebServer handles this internally


🎯 Recommended Action Plan

Priority 1 (Breaks builds):

  1. Already fixed: LEDC API in bus_manager.cpp and PWM_fan.cpp
  2. ⚠️ Still broken: pwm_outputs usermod needs LEDC guards
  3. ⚠️ Conditionally broken: util.cpp generateDeviceFingerprint() needs headers/guards

Priority 2 (Generates warnings):

  1. Fix ADC_ATTEN_DB_11ADC_ATTEN_DB_12 (2 locations)
  2. Add ESP-IDF version guards to deep_sleep usermod RTC GPIO calls

Priority 3 (Future-proofing):

  1. Consider migrating heap_caps_get_* to heap_caps_get_info() in a future cleanup
  2. Document that audioreactive usermod requires I2S driver migration for V5

What's Already Working Well

The codebase shows good V4/V5 compatibility patterns in:

  • ✅ Network class rename (Network → WLEDNetwork) - complete
  • ✅ mbedtls SHA1 shim - working solution
  • ✅ LEDC API guards in core files (bus_manager, PWM_fan)
  • ✅ DMX driver updated for V5 API changes
  • ✅ Ethernet ETH.begin() parameter order fixed
  • ✅ RMT conflict mitigation via -DESP32_ARDUINO_NO_RGB_BUILTIN

Overall assessment: The V5 migration is ~90% complete. The remaining issues are concentrated in:

  1. One core file (util.cpp chip ID function)
  2. Two usermods (pwm_outputs, deep_sleep)
  3. One intentionally disabled subsystem (audioreactive)

Would you like me to generate specific patch proposals for the Priority 1 issues?


🧠 Learnings used
Learnt from: Jason2866
Repo: wled/WLED PR: 4838
File: requirements.txt:2-2
Timestamp: 2025-12-01T16:13:06.613Z
Learning: Python 3.13 is supported by ESP-IDF 5.x and PlatformIO (any version including 6.1.18+), contrary to some incomplete documentation. This was confirmed by project maintainer Jason2866 in the WLED repository.

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: 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: 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: 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: 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: 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: 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: blazoncek
Repo: wled/WLED PR: 4482
File: wled00/udp.cpp:147-149
Timestamp: 2025-02-19T12:43:34.199Z
Learning: ESP8266 and ESP32 platforms have different maximum segment name lengths in WLED, which can cause truncation when syncing segment names between devices. This platform difference affects the user experience when using the segment name sync feature.

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

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 7

Caution

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

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

1135-1229: ⚠️ Potential issue | 🟠 Major

Blanket IDF v5 exclusion disables all three functions unnecessarily — computeSHA1 and getDeviceId can work with targeted API guards.

The #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) guard removes computeSHA1, generateDeviceFingerprint, and getDeviceId on IDF v5, but only two compatibility issues exist:

  1. mbedtls API rename (lines 1147–1149): In IDF v5's mbedtls 3.x, the _ret suffix was removed. Use conditional compilation to select the correct function names:

    • Old (IDF <5): mbedtls_sha1_starts_ret(), mbedtls_sha1_update_ret(), mbedtls_sha1_finish_ret()
    • New (IDF ≥5): mbedtls_sha1_starts(), mbedtls_sha1_update(), mbedtls_sha1_finish() (still return int)
  2. esp_adc_cal.h removal (line 1164): Replaced by esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h with a redesigned API; only affects generateDeviceFingerprint.

A targeted approach allows computeSHA1 and getDeviceId to work on IDF v5 immediately:

Suggested fix for computeSHA1
 String computeSHA1(const String& input) {
   `#ifdef` ESP8266
     return sha1(input);
   `#else`
     unsigned char shaResult[20];
     mbedtls_sha1_context ctx;
     mbedtls_sha1_init(&ctx);
+  `#if` ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
+    mbedtls_sha1_starts(&ctx);
+    mbedtls_sha1_update(&ctx, (const unsigned char*)input.c_str(), input.length());
+    mbedtls_sha1_finish(&ctx, shaResult);
+  `#else`
     mbedtls_sha1_starts_ret(&ctx);
     mbedtls_sha1_update_ret(&ctx, (const unsigned char*)input.c_str(), input.length());
     mbedtls_sha1_finish_ret(&ctx, shaResult);
+  `#endif`
     mbedtls_sha1_free(&ctx);
     // ... hex conversion unchanged
   `#endif`
 }
🤖 Fix all issues with AI agents
In `@platformio.ini`:
- Around line 278-283: The build_unflags assignment is wrong: it uses
${esp32_idf_V5.build_flags} which cancels flags; change the value to
${esp32_idf_V5.build_unflags} so build_unflags references the unflag list from
the esp32_idf_V5 section; update the platformio.ini entry that defines
build_unflags (near the lines with platform, build_flags, lib_deps) to use
${esp32_idf_V5.build_unflags} instead of ${esp32_idf_V5.build_flags}.
- Line 130: The build flag WLED_USE_SHARED_RMT is defined multiple times; remove
the definitions from the common build_flags and keep a single definition in the
esp32_idf_V5 build_flags block (or if you want it to apply everywhere, remove
the duplicates in esp32_idf_V5 and keep it only in common). Edit the
platformio.ini to ensure WLED_USE_SHARED_RMT appears exactly once and only
within the intended scope by deleting the extra entries in the
[common].build_flags or the duplicate(s) in [esp32_idf_V5].build_flags.
- Around line 387-404: The [esp32s3] environment is missing the proper unflags
and lib exclusion: replace the incorrect reference to ${common.build_unflags}
with ${esp32_idf_V5.build_unflags} (so the -Wno-volatile unflag is applied to C
files) and add the same lib_ignore entry used in other ESP32 envs (e.g.
${esp32_idf_V5.lib_ignore}) to exclude NeoESP32RmtHI from S3 builds to avoid RMT
driver conflicts; update the build_unflags and add lib_ignore under the
[esp32s3] block.

In `@wled00/dmx_input.cpp`:
- Around line 95-129: Define a named constant like DMX_PERSONALITY_COUNT and
replace the hardcoded 10 in the static array declaration (currently static
dmx_personality_t personalities[10];), in createPersonalities usage, and in
calls to dmx_driver_install and rdm_register_dmx_personality so all three sites
use DMX_PERSONALITY_COUNT; update any loops or bounds that assume 10 to
reference DMX_PERSONALITY_COUNT and ensure the constant is visible where
dmx_driver_install and rdm_register_dmx_personality are invoked.
- Around line 86-93: In createConfig(), config.software_version_label is set to
DmxVersionString.c_str() which leaves a dangling pointer when the local
std::string DmxVersionString is destroyed; fix by copying the string into the
config's fixed-size char buffer (e.g., use
strncpy(config.software_version_label, DmxVersionString.c_str(),
sizeof(config.software_version_label)-1) and set the final byte to '\0') so the
label remains valid after createConfig() returns; alternatively, if
config.software_version_label is a const char* and you prefer a static lifetime,
replace DmxVersionString with a static std::string or a static char array, but
prefer the strncpy approach to avoid global state.

In `@wled00/network.cpp`:
- Around line 234-241: The ETH.begin(...) call uses the v5/Arduino-ESP32
parameter order and needs a conditional to preserve v4 compatibility; wrap the
call to ETH.begin in a version/build guard (e.g., check CONFIG_IDF_VERSION_MAJOR
or the esp32dev_V4 define) and call ETH.begin with the v5 signature when IDF v5
is detected (using es.eth_type, es.eth_address, es.eth_mdc, es.eth_mdio,
es.eth_power, es.eth_clk_mode) but use the v4 signature when building for
esp32dev_V4/IDF v4 (placing phy_addr/eth_address as the first parameter and
ordering the rest per the v4 API) so compilation succeeds on both IDF versions.

In `@wled00/src/dependencies/espalexa/Espalexa.h`:
- Line 273: The lambda passed to serverAsync->on that handles HTTP_GET still
uses an implicit-capture `[=]`; change its capture to `[this]` to match the
other handlers and avoid implicit `this` capture warnings — i.e. update the
lambda used in the serverAsync->on("/espalexa", HTTP_GET, ...) callback that
assigns to `server` and calls `servePage()` so it captures `this` explicitly
(use `[this]`), leaving the parameter `AsyncWebServerRequest *request`
unchanged.
🧹 Nitpick comments (5)
wled00/src/dependencies/espalexa/Espalexa.h (1)

21-26: Dummy macro value is misleading but currently harmless.

The real ESP_IDF_VERSION_VAL encodes as (major << 16) | (minor << 8) | patch, so ESP_IDF_VERSION_VAL(5,0,0) = 327680, not 500. Since the only comparison site (line 389) is guarded by defined(ARDUINO_ARCH_ESP32), this value is never evaluated on ESP8266, so it won't cause a bug today. But if anyone later adds a version check without the ESP32 guard, the result will be silently wrong.

Suggested fix
-#define ESP_IDF_VERSION_VAL(n1,n2,n3) 500
+#define ESP_IDF_VERSION_VAL(n1,n2,n3) ((n1 << 16) | (n2 << 8) | (n3))
platformio.ini (2)

504-522: esp32dev_V4 unflags WLED_ENABLE_DMX_INPUT which may not exist at that point.

Line 510 uses build_unflags with -D WLED_ENABLE_DMX_INPUT, but build_unflags on line 509 inherits ${common.build_unflags} which is empty. The DMX flag comes from ${esp32_idf_V4.build_flags} (line 313), so it's being added and unflagged in the same env. This works in PlatformIO but the intent would be clearer by simply not including the flag in the first place via a V4-specific override.

Otherwise the V4 regression test environment looks reasonable.


13-39: Several entries in default_envs are both commented and uncommented.

esp32s3dev_8MB_opi appears uncommented on line 36 and commented on line 31. esp32s3dev_16MB_opi and esp32s3_4M_qspi similarly appear commented in two places (lines 30+35 and 32+38). This makes it hard to tell which S3 builds are actually active. Consider cleaning up to have each env listed once.

wled00/fcn_declare.h (1)

5-10: Dummy ESP_IDF_VERSION_VAL returns a misleading magic number.

The shim defines ESP_IDF_VERSION_VAL(n1,n2,n3) as 500, which doesn't match the real macro's formula ((n1<<16)|(n2<<8)|n3). While it currently works because ESP8266 guards short-circuit before evaluating IDF version comparisons, any future direct use on ESP8266 (e.g., ESP_IDF_VERSION_VAL(1,0,0)) would yield 500 instead of 65536, leading to silently wrong comparisons.

Consider matching the real formula or using a clearly-below-everything sentinel like 0:

Suggested fix
 // dummy macro for 8266
 `#ifndef` ARDUINO_ARCH_ESP32
 `#ifndef` ESP_IDF_VERSION_VAL
-#define ESP_IDF_VERSION_VAL(n1,n2,n3) 500
+#define ESP_IDF_VERSION_VAL(n1,n2,n3) ((n1 << 16) | (n2 << 8) | n3)
+#endif
+#ifndef ESP_IDF_VERSION
+#define ESP_IDF_VERSION 0
 `#endif`
 `#endif`
wled00/dmx_input.cpp (1)

100-128: Use sizeof(personalities[0].description) instead of hardcoded 32 for strncpy buffer size.

The description field in dmx_personality_t is 33 bytes (32 chars + null terminator). While the current code happens to work because personalities is zero-initialized and all strings are shorter than 32 characters, using sizeof(personalities[0].description) would be more defensive and prevent potential issues if string lengths change in the future.

Comment on lines +86 to 93
#else
// fallback code
const std::string DmxVersionString = "WLED_V" + std::to_string(VERSION);
config.software_version_label = DmxVersionString.c_str();
#endif

return config;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Dangling pointer: config.software_version_label points to destroyed local std::string.

DmxVersionString is a local std::string inside createConfig(). Assigning .c_str() to config.software_version_label and then returning config leaves the pointer dangling — the string's buffer is freed when the function returns. This is undefined behavior and will likely cause garbage or a crash when the label is read.

Proposed fix — use `strncpy` into a fixed-size field, or make the string `static`
   `#else`
     // fallback code
-    const std::string DmxVersionString = "WLED_V" + std::to_string(VERSION);
-    config.software_version_label = DmxVersionString.c_str();
+    static std::string DmxVersionString = "WLED_V" + std::to_string(VERSION);
+    config.software_version_label = DmxVersionString.c_str();
   `#endif`
🤖 Prompt for AI Agents
In `@wled00/dmx_input.cpp` around lines 86 - 93, In createConfig(),
config.software_version_label is set to DmxVersionString.c_str() which leaves a
dangling pointer when the local std::string DmxVersionString is destroyed; fix
by copying the string into the config's fixed-size char buffer (e.g., use
strncpy(config.software_version_label, DmxVersionString.c_str(),
sizeof(config.software_version_label)-1) and set the final byte to '\0') so the
label remains valid after createConfig() returns; alternatively, if
config.software_version_label is a const char* and you prefer a static lifetime,
replace DmxVersionString with a static std::string or a static char array, but
prefer the strncpy approach to avoid global state.

Comment on lines +95 to +129
static dmx_personality_t personalities[10];

static void createPersonalities()
{
// Initialize personalities array
strncpy(personalities[0].description, "SINGLE_RGB", 32);
personalities[0].footprint = 3;

strncpy(personalities[1].description, "SINGLE_DRGB", 32);
personalities[1].footprint = 4;

strncpy(personalities[2].description, "EFFECT", 32);
personalities[2].footprint = 15;

strncpy(personalities[3].description, "MULTIPLE_RGB", 32);
personalities[3].footprint = std::min(512, int(strip.getLengthTotal()) * 3);

strncpy(personalities[4].description, "MULTIPLE_DRGB", 32);
personalities[4].footprint = std::min(512, int(strip.getLengthTotal()) * 3 + 1);

strncpy(personalities[5].description, "MULTIPLE_RGBW", 32);
personalities[5].footprint = std::min(512, int(strip.getLengthTotal()) * 4);

strncpy(personalities[6].description, "EFFECT_W", 32);
personalities[6].footprint = 18;

strncpy(personalities[7].description, "EFFECT_SEGMENT", 32);
personalities[7].footprint = std::min(512, strip.getSegmentsNum() * 15);

strncpy(personalities[8].description, "EFFECT_SEGMENT_W", 32);
personalities[8].footprint = std::min(512, strip.getSegmentsNum() * 18);

strncpy(personalities[9].description, "PRESET", 32);
personalities[9].footprint = 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Magic number 10 repeated for personality count — extract a named constant.

The literal 10 appears in the static array size (Line 95), dmx_driver_install (Line 151), and rdm_register_dmx_personality (Line 167). If one site is updated but not the others, it silently breaks. A single constant keeps them in sync.

Proposed refactor
+static constexpr size_t DMX_PERSONALITY_COUNT = 10;
+
-static dmx_personality_t personalities[10];
+static dmx_personality_t personalities[DMX_PERSONALITY_COUNT];

Then use DMX_PERSONALITY_COUNT in dmx_driver_install and rdm_register_dmx_personality calls as well.

Also applies to: 148-151, 167-167

🤖 Prompt for AI Agents
In `@wled00/dmx_input.cpp` around lines 95 - 129, Define a named constant like
DMX_PERSONALITY_COUNT and replace the hardcoded 10 in the static array
declaration (currently static dmx_personality_t personalities[10];), in
createPersonalities usage, and in calls to dmx_driver_install and
rdm_register_dmx_personality so all three sites use DMX_PERSONALITY_COUNT;
update any loops or bounds that assume 10 to reference DMX_PERSONALITY_COUNT and
ensure the constant is visible where dmx_driver_install and
rdm_register_dmx_personality are invoked.

@softhack007
Copy link
Member

@coderabbitai i need a concise summary of open points in this PR.
Please scan all unresolved comments, and all discussions with open ends. Create a summary list with major open points, grouped by WLED features or files. For each entry in the list, add a link the relevant comment for more information.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

Tip

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

@softhack007: Here's a concise summary of open points in this PR, organized by area:


🔧 Core WLED Code Issues

1. util.cpp - Device Identification Functions

Status: ❌ Broken in V5 builds (conditionally compiled out)

  • Missing headers for esp_chip_info(), esp_efuse_mac_get_default()
  • computeSHA1() and getDeviceId() disabled for ESP-IDF ≥5.0
  • Impact: Device fingerprinting not working in V5
  • Reference: Build error comment | My analysis

2. ADC Deprecated Constants

Status: ⚠️ Generates compiler warnings

  • ADC_ATTEN_DB_11 used in util.cpp:1177 and audioreactive
  • Should be replaced with ADC_ATTEN_DB_12
  • Reference: My analysis - Priority 2

🏗️ Build System & Tooling

3. PlatformIO Instability

Status: ⚠️ Intermittent build failures

  • pioarduino packages sneaking into builds
  • Short SHA library references randomly failing (#bc3af18)
  • Workaround: Delete ~/.platformio and restart
  • Action needed: Replace short hashes with long hashes or .zip references
  • Reference: PlatformIO issues comment | Jason2866's recommendation

4. Usermod CI Builds

Status: ⏸️ Generating ~100 extra builds

5. Platform Package Decision

Status: 🤔 Strategy discussion needed

  • Current: Using Tasmota platform package
  • Alternative: Switch to pioarduino for better V5 support
  • Action needed: Decide on primary platform package
  • Reference: pioarduino discussion

🔌 Usermods Compatibility

6. pwm_outputs Usermod

Status: ❌ Missing LEDC API guards

  • Uses old ledcSetup()/ledcAttachPin() without ESP-IDF version checks
  • Needs same fix as PWM_fan usermod
  • Reference: My analysis - Priority 1

7. deep_sleep Usermod

Status: ⚠️ Unguarded RTC GPIO APIs

  • Multiple rtc_gpio_*() calls without version protection
  • May break on future ESP-IDF updates
  • Reference: My analysis - Priority 2

8. audioreactive Usermod

Status: 🚧 Disabled for V5

  • Requires I2S driver migration (major API changes in IDF 5)
  • ADC_ATTEN_DB_11 deprecation warning
  • Reference: Mentioned in usermod CI analysis

9. Usermod Registration Mechanism

Status: ✅ Fixed with hybrid approach


📚 External Dependencies

10. NeoPixelBus/RMT Driver Conflicts

Status: ✅ Mitigated with build flag

11. mbedtls SHA1 Functions

Status: ✅ Fixed with shim


🎯 Action Items Summary

Critical (breaks builds):

  1. Fix pwm_outputs usermod LEDC API usage
  2. Fix util.cpp device ID functions for V5
  3. Replace short SHA hashes in dependencies

Important (warnings/future-proofing):
4. Replace ADC_ATTEN_DB_11 with ADC_ATTEN_DB_12
5. Add ESP-IDF guards to deep_sleep RTC GPIO calls
6. Disable Usermod CI for V5 branch

Strategic decisions needed:
7. Confirm platform package strategy (Tasmota vs pioarduino)
8. Plan audioreactive I2S driver migration


Would you like me to create GitHub issues for the critical action items, or generate patch proposals for items #1 and #2?


🧠 Learnings used
Learnt from: Jason2866
Repo: wled/WLED PR: 4838
File: requirements.txt:2-2
Timestamp: 2025-12-01T16:13:06.613Z
Learning: Python 3.13 is supported by ESP-IDF 5.x and PlatformIO (any version including 6.1.18+), contrary to some incomplete documentation. This was confirmed by project maintainer Jason2866 in the WLED repository.

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: 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: 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: blazoncek
Repo: wled/WLED PR: 4482
File: wled00/udp.cpp:147-149
Timestamp: 2025-02-19T12:43:34.199Z
Learning: ESP8266 and ESP32 platforms have different maximum segment name lengths in WLED, which can cause truncation when syncing segment names between devices. This platform difference affects the user experience when using the segment name sync feature.

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: 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: 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: 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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants