Skip to content

Conversation

DedeHai
Copy link
Collaborator

@DedeHai DedeHai commented Sep 16, 2025

  • added some safety checks for UI to not throw errors if JSON parameters are missing to prevent UI being fully stuck
    edit: reverted these changes in favour for a better (future) solution to not use any parallel requests which solves it in a better way

  • add all buses in config even - divert to "dummy" bus if RAM limit is exceeded (thx @willmmiles )

  • improved heap checker in main loop: checks heap once every second and takes action only if limit is exceeded continuously (prevents false triggers)

  • added a variable to prevent wifi re-init during OTA

fixes #4936

this is mostly what codepilot came up with.

Summary by CodeRabbit

  • New Features

    • Continues operating when LED memory/channel limits are exceeded by adding placeholder buses that preserve configuration and UI visibility.
    • Staged low‑memory protection with progressive actions (simplify effects, recreate segments, full strip reset) to maintain stability.
  • Bug Fixes

    • Ensures a default segment is recreated if segments are lost due to low memory.
    • More robust handling of bus/segment data for UI and settings generation to avoid crashes or undefined access.

- added some safety checks for UI to not throw errors if JSCON parameters are missing
- add all buses in config even if they exceed RAM limit, truncates long buses
Copy link
Contributor

coderabbitai bot commented Sep 16, 2025

Walkthrough

Adds a BusPlaceholder type and extends BusManager::add to allow placeholder buses when memory/channel limits are hit; WS2812FX initialization now creates placeholders instead of aborting, relaxes isOk() gating in several loops, and increases staged heap-monitoring with multi-threshold recovery actions.

Changes

Cohort / File(s) Summary of changes
WS2812FX init & segments
wled00/FX_fcn.cpp
finalizeInit iterates busConfigs by value, computes per-bus memory, requests BusManager::add(..., placeholder) when limits would be exceeded, marks placeholder buses instead of failing, updates _length/_hasWhiteChannel/_isOffRefreshRequired, begins buses, applies brightness, initializes ABL, clears configs; resetSegments ensures a default segment if list empty; makeAutoSegments stops on null bus.
Bus manager & placeholder
wled00/bus_manager.h, wled00/bus_manager.cpp
Adds new BusPlaceholder class (stores config, exposes pins and getters, no-op pixel/show), introduces Bus::isPlaceholder virtual, changes BusManager::add signature to add(const BusConfig&, bool placeholder), creates BusPlaceholder when over limits; getLength no longer gated on isOk(); on()/initializeABL() only act on isOk() digital buses.
Serialization & settings loops
wled00/cfg.cpp, wled00/xml.cpp
Changed bus iteration guards from `if (!bus
Heap monitoring & staged recovery
wled00/wled.cpp
Replaced previous heap tracking with per-second checks using arch-specific free-heap APIs, added heapDanger counter and staged responses at 15/30/45 consecutive low-heap seconds (purge/static, resetSegments, full reset + WiFi reconnect) and sets ERR_NORAM accordingly.
Web UI minor change
wled00/data/index.js
Small (effectively no-op) change to an event listener line; overall UI guards noted in summary but diff shows minimal listener edit.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • willmmiles
  • blazoncek

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Fix for cfg exceeding LED limit" directly references the core issue #4936, which describes the problem of losing LED output and UI functionality when configured buses exceed MAX_LED_MEMORY. The title clearly identifies this primary fix for the changeset. While the PR scope extends beyond just this fix to include heap improvements and UI safety measures, the title appropriately captures the essential issue being resolved. The title is specific enough to convey the main purpose without being misleading.
Linked Issues Check ✅ Passed The pull request addresses the core requirements from issue #4936. The introduction of the BusPlaceholder class (bus_manager.h, bus_manager.cpp) directly implements the fallback mechanism when digital buses cannot be created due to memory limits, preventing total loss of LED output. Changes to cfg.cpp and xml.cpp remove isOk() gatekeeping from serialization logic, ensuring failed buses remain visible and editable in the UI, preserving user configuration visibility as required. The FX_fcn.cpp modifications handle memory limit scenarios by creating placeholder buses instead of failing outright, maintaining device usability. The changes collectively address preventing web UI failure, providing a fallback for buses exceeding limits, and keeping the device operational when configured LEDs exceed MAX_LED_MEMORY.
Out of Scope Changes Check ✅ Passed Most changes are directly related to the core requirement of handling buses exceeding memory limits. The placeholder bus implementation and serialization guard modifications address issue #4936's primary concerns. However, the PR scope extends beyond the specific issue to include heap management improvements (wled.cpp multi-threshold response, architecture-specific checks) and an OTA WiFi re-initialization safeguard that go beyond the stated requirements of #4936 itself, though these are mentioned in the PR objectives as part of the overall robustness strategy. Additionally, the data/index.js change appears minimal with no observable effect, making its necessity unclear. The broader architectural changes to FX_fcn.cpp (finalizeInit refactoring, makeAutoSegments logic) are justified as necessary for placeholder implementation.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac529e7 and 70015bf.

📒 Files selected for processing (1)
  • wled00/data/index.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • wled00/data/index.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full)
  • GitHub Check: wled_build / Build Environments (esp8266_2m)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_compat)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)

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.

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

🧹 Nitpick comments (2)
wled00/data/index.js (2)

926-944: populateSegments guards — solid hardening, tiny nit

Good null checks around seg deletion/power controls. Consider explicit radix in parseInt for clarity across engines.

-    if (seg0briElement && segp0Element && parseInt(seg0briElement.value)==255) segp0Element.classList.add("hide");
+    if (seg0briElement && segp0Element && parseInt(seg0briElement.value, 10) === 255) segp0Element.classList.add("hide");

2409-2415: Typo in warning; keep message clear

Fix “elemen” → “element”.

-  console.warn('No power elemen');
+  console.warn('No power element');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76cb2e9 and db310c6.

📒 Files selected for processing (2)
  • wled00/FX_fcn.cpp (1 hunks)
  • wled00/data/index.js (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use tabs for indentation in web UI files (.htm/.html/.css/.js) under wled00/data

Files:

  • wled00/data/index.js
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware files

Files:

  • wled00/FX_fcn.cpp
🧠 Learnings (4)
📚 Learning: 2025-04-24T09:31:06.879Z
Learnt from: blazoncek
PR: wled/WLED#4658
File: wled00/led.cpp:90-91
Timestamp: 2025-04-24T09:31:06.879Z
Learning: In the WLED codebase, the `getSegment()` function guards against out-of-bounds segment IDs, and `getFirstSelectedSegId()` falls back to `getMainSegmentId()` if no segments are selected, ensuring no crashes when used through the `setValuesFromFirstSelectedSeg()` macro.

Applied to files:

  • wled00/data/index.js
📚 Learning: 2025-04-24T09:31:06.879Z
Learnt from: blazoncek
PR: wled/WLED#4658
File: wled00/led.cpp:90-91
Timestamp: 2025-04-24T09:31:06.879Z
Learning: In the WLED codebase, the `getSegment()` function guards against out-of-bounds segment IDs by falling back to the main segment ID, and `getFirstSelectedSegId()` falls back to `getMainSegmentId()` if no segments are selected, ensuring no crashes when used through the `setValuesFromFirstSelectedSeg()` macro.

Applied to files:

  • wled00/data/index.js
📚 Learning: 2025-09-12T17:29:43.793Z
Learnt from: DedeHai
PR: wled/WLED#4923
File: wled00/FX.cpp:4883-4901
Timestamp: 2025-09-12T17:29:43.793Z
Learning: In WLED’s web UI, only one slider value (e.g., SEGMENT.intensity or SEGMENT.custom1) changes at a time; code relying on this may use simplified change guards, though presets/JSON can still update multiple fields atomically.

Applied to files:

  • wled00/data/index.js
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#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.

Applied to files:

  • wled00/FX_fcn.cpp
🧬 Code graph analysis (1)
wled00/FX_fcn.cpp (2)
wled00/bus_manager.h (3)
  • isDigital (141-142)
  • isDigital (180-180)
  • is2Pin (181-181)
wled00/bus_manager.cpp (4)
  • add (82-87)
  • add (82-82)
  • add (806-827)
  • add (806-806)
🔇 Additional comments (2)
wled00/data/index.js (2)

671-684: Graceful defaults for missing LED metadata — LGTM

Defensive checks for i.leds.count and i.leds.maxseg prevent UI crashes and use sane fallbacks. Indentation complies with tabs.


2280-2282: rptSeg: safe read of power state — LGTM

Fallback to false when the power element is absent avoids exceptions.

@willmmiles
Copy link
Member

Truncating too long buses is not OK -- it creates the weird behavior that the configuration "mutates" when saved by the user. (Why won't my settings stick??) I think what we need to do is create a placeholder bus object (BusPlaceholder?) that doesn't actually do anything, but carries forward the settings for later inspection.

(We should probably also consider removing the Bus::isOk() checks in getSettingsJS() and serializeConfig() -- that way failed buses can still be edited in the settings page as well.)

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 17, 2025

Truncating too long buses is not OK -- it creates the weird behavior that the configuration "mutates" when saved by the user. (Why won't my settings stick??) I think what we need to do is create a placeholder bus object (BusPlaceholder?) that doesn't actually do anything, but carries forward the settings for later inspection.

(We should probably also consider removing the Bus::isOk() checks in getSettingsJS() and serializeConfig() -- that way failed buses can still be edited in the settings page as well.)

very good point, I saw that and thought the same thing but did not think about a solution yet. Any suggestion in how to preserve the config?

Copy link
Collaborator

@blazoncek blazoncek left a comment

Choose a reason for hiding this comment

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

I would have fixed the count issues in finalizeInit() instead.

DEBUG_PRINTF_P(PSTR("Bus %d memory usage exceeds limit, setting count to %d\n"), (int)bus.type, bus.count);
}
if (BusManager::add(bus) != -1) {
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount : 0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need to estimate when you have bus already created.
Use BusManager::getBus(BusManager::getNumBusses()-1)->getBusSize(); instead.

@willmmiles
Copy link
Member

very good point, I saw that and thought the same thing but did not think about a solution yet. Any suggestion in how to preserve the config?

Make up a new Bus subclass BusPlaceholder (or some better name) that ignores the IO calls (_valid is false, pure virtuals are no-ops) but retains the relevant config data. Then, in finalizeInit, if a bus will exceed the memory limit, we add a BusPlaceholder instead. Since the "type" value gets preserved, future round-trips through finalizeInit will attempt to create the "correct" bus class first.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 17, 2025

Make up a new Bus subclass BusPlaceholder (or some better name) that ignores the IO calls (_valid is false, pure virtuals are no-ops) but retains the relevant config data. Then, in finalizeInit, if a bus will exceed the memory limit, we add a BusPlaceholder instead. Since the "type" value gets preserved, future round-trips through finalizeInit will attempt to create the "correct" bus class first.

thanks, I need to process that. Working on heap/ram stuff RN so this is on backburner. If you have the time and interest, feel free to contribute directly to this PR.

In the event that a Bus fails to initialize, or the memory validation
fails, keep the configuration around so the settings contents don't
change out from under the user.
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: 1

Caution

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

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

1198-1204: Don’t stop initializing after the first placeholder

Breaking on the first non-OK bus prevents later valid buses from being begun, causing unexpected loss of output. Continue past placeholders instead.

-    if (!bus || !bus->isOk() || bus->getStart() + bus->getLength() > MAX_LEDS) break;
+    if (!bus) break;
+    if (!bus->isOk() || bus->getStart() + bus->getLength() > MAX_LEDS) continue;
wled00/bus_manager.cpp (1)

820-844: Channel-limit check ignores the new bus; enforce “would exceed” correctly

The current test uses existing counts only, so it never triggers. Include the pending bus in the calculation.

-  if (digital > WLED_MAX_DIGITAL_CHANNELS || analog > WLED_MAX_ANALOG_CHANNELS) placeholder = true;
+  const bool newIsDigital   = Bus::isDigital(bc.type) && !Bus::is2Pin(bc.type);
+  const bool newIsAnalogPWM = Bus::isPWM(bc.type);
+  const unsigned newAnalogPins = newIsAnalogPWM ? Bus::numPWMPins(bc.type) : 0;
+  if ((digital + (newIsDigital ? 1 : 0)) > WLED_MAX_DIGITAL_CHANNELS ||
+      (analog  + newAnalogPins)         > WLED_MAX_ANALOG_CHANNELS) {
+    placeholder = true;
+  }
🧹 Nitpick comments (1)
wled00/FX_fcn.cpp (1)

1749-1765: Replace early break on non-OK buses with continue (skip placeholders, don't mask later buses)

Replace:

-    if (!bus || !bus->isOk()) break;
+    if (!bus) break;
+    if (!bus->isOk()) continue;

Apply in wled00/FX_fcn.cpp at lines 986, 1751, 1761, 1898.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97f68b3 and f8ca0f9.

📒 Files selected for processing (5)
  • wled00/FX_fcn.cpp (2 hunks)
  • wled00/bus_manager.cpp (5 hunks)
  • wled00/bus_manager.h (3 hunks)
  • wled00/cfg.cpp (1 hunks)
  • wled00/xml.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware files

Files:

  • wled00/xml.cpp
  • wled00/cfg.cpp
  • wled00/bus_manager.cpp
  • wled00/FX_fcn.cpp
  • wled00/bus_manager.h
🧠 Learnings (11)
📓 Common learnings
Learnt from: DedeHai
PR: wled/WLED#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.
📚 Learning: 2025-09-16T18:08:42.848Z
Learnt from: DedeHai
PR: wled/WLED#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.

Applied to files:

  • wled00/xml.cpp
  • wled00/cfg.cpp
  • wled00/bus_manager.cpp
  • wled00/FX_fcn.cpp
  • wled00/bus_manager.h
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#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.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-08-28T08:09:20.630Z
Learnt from: mval-sg
PR: wled/WLED#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.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-04-30T05:41:03.633Z
Learnt from: blazoncek
PR: wled/WLED#4667
File: usermods/user_fx/user_fx.cpp:27-30
Timestamp: 2025-04-30T05:41:03.633Z
Learning: In WLED, the Segment::allocateData() method already includes optimization to check if data is allocated and sufficiently sized, handling buffer reuse to reduce memory fragmentation. Adding an external check like `if (SEGENV.data == nullptr && !SEGENV.allocateData(dataSize))` is unnecessary and could be problematic, as it bypasses proper size verification.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-08-31T03:38:14.114Z
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-09-02T01:56:43.841Z
Learnt from: willmmiles
PR: wled/WLED#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.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-09-15T19:13:56.469Z
Learnt from: DedeHai
PR: wled/WLED#4791
File: wled00/util.cpp:737-743
Timestamp: 2025-09-15T19:13:56.469Z
Learning: In WLED's util.cpp, the *_realloc_malloc functions (p_realloc_malloc and d_realloc_malloc) are intentionally designed to free the original buffer on realloc failure and allocate a new buffer, implementing a "replace buffer" semantic rather than traditional realloc behavior. This is documented in the function comments and is the intended design by the author DedeHai.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-08-29T15:38:46.208Z
Learnt from: DedeHai
PR: wled/WLED#4791
File: wled00/FX_fcn.cpp:1187-1191
Timestamp: 2025-08-29T15:38:46.208Z
Learning: In WLED's allocate_buffer() function, BFRALLOC_ENFORCE_PSRAM already includes fallback logic to DRAM if PSRAM is not available, as documented in the comment "use PSRAM if available, otherwise fall back to DRAM". The function also uses validateFreeHeap() for additional safety checks. During setup() when finalizeInit() runs, PSRAM has vast available memory making failures unlikely.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-09-01T10:26:17.959Z
Learnt from: mval-sg
PR: wled/WLED#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.

Applied to files:

  • wled00/FX_fcn.cpp
📚 Learning: 2025-08-21T00:00:17.196Z
Learnt from: willmmiles
PR: wled/WLED#4859
File: usermods/udp_name_sync/udp_name_sync.cpp:62-70
Timestamp: 2025-08-21T00:00:17.196Z
Learning: In WLED codebase, UDP packet processing code must never rely on null termination being present on the wire and must always validate packet size first. The codebase already has some vulnerabilities where malformed data can crash the software, so avoiding introduction of new ones is a priority.

Applied to files:

  • wled00/FX_fcn.cpp
🧬 Code graph analysis (3)
wled00/bus_manager.cpp (1)
wled00/bus_manager.h (4)
  • BusPlaceholder (368-395)
  • getNumberOfPins (161-161)
  • isVirtual (145-146)
  • isVirtual (184-184)
wled00/FX_fcn.cpp (2)
wled00/bus_manager.h (3)
  • isDigital (141-142)
  • isDigital (180-180)
  • is2Pin (181-181)
wled00/bus_manager.cpp (4)
  • add (76-81)
  • add (76-76)
  • add (820-843)
  • add (820-820)
wled00/bus_manager.h (1)
wled00/bus_manager.cpp (15)
  • BusPlaceholder (758-768)
  • getPins (320-324)
  • getPins (320-320)
  • getPins (575-580)
  • getPins (575-575)
  • getPins (647-651)
  • getPins (647-647)
  • getPins (716-719)
  • getPins (716-716)
  • getPins (770-776)
  • getPins (770-770)
  • add (76-81)
  • add (76-76)
  • add (820-843)
  • add (820-820)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
🔇 Additional comments (11)
wled00/xml.cpp (1)

317-317: Good: allow placeholders to flow to UI

Switching to a null-only break lets non-OK buses (placeholders) be serialized into settings JS. This aligns with the placeholder design.

Please confirm the UI correctly displays pins for placeholders even if PinManager::isPinOk(pin) returns false; otherwise consider printing stored pins unconditionally for placeholders.

wled00/cfg.cpp (1)

973-980: Serialize non-OK buses too — matches placeholder approach

Dropping the isOk() guard here ensures placeholder buses get saved back to cfg.json, avoiding “mutating” config.

wled00/FX_fcn.cpp (1)

1810-1811: LGTM: auto-segmentation tolerates placeholders

Keeping only a null check avoids skipping segments when a placeholder appears.

wled00/bus_manager.cpp (5)

758-769: LGTM: BusPlaceholder preserves config

Constructor copies all user config (pins, order, current, etc.). Defaults keep _valid=false, as intended.


770-776: LGTM: getPins exposes stored pins for UI/serialization

Matches Bus::getNumberOfPins(type).


933-936: LGTM: avoid touching placeholders during ESP8266 LED_BUILTIN re-init

Added isOk() gate prevents placeholder interaction.


1027-1036: LGTM: ABL setup skips placeholders

Only OK digital buses get current limits.


1072-1077: LGTM: ABL apply loops only real digital buses

Prevents placeholder side effects.

wled00/bus_manager.h (3)

128-128: Changed getLength() to always return _len — verify callers

This is necessary for placeholders, but check that length aggregations (e.g., BusManager::getTotalLength(false)) aren’t surfaced in places where “physical” length is expected. Use getTotalLength(true) or isOk() where appropriate.


366-395: LGTM: Placeholder class surface is sufficient for UI and cfg

No-ops for IO, full accessors for config. Minor: matching the base default arg for getPins is optional, current override is fine.


499-499: Signature change acknowledged

add(const BusConfig&, bool) is fine; ensure all call sites use the new flag (you updated finalizeInit()).

@blazoncek
Copy link
Collaborator

@willmmiles IMO there is no need to complicate things with bus placeholder. The only thing needed to be done is ignore isOk() on some places and proceed without memory allocation and underlying physical bus initialisation.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 18, 2025

I did some experimenting in my dev branch and I think I have a good overall solution for ESP8266. It goes something like this:

  • the UI as well as finalizeInit() do not take the MAX_LED_MEMORY as a hard limit since we also need buffers and those are not all obligatory
  • instead the UI takes the MAX_LED_MEMORY to throw warnings at the user and denies writing the config if double that limit is exceeded, i.e. bus+globalbuffer+segmentbuffer (with a warning message that it cannot be handled).
  • finalizeInit() uses the same approach but has a slightly lower estimate to make sure buses get added if UI does not deny it
  • for existing configs that would exceed the limit the bus length gets truncated (thx @willmmiles for taking the effort)

still need to test how that behaves on ESP32 and maybe tweak it a little. For ESP8266 the new limit is about 720 WS281x LEDs, everything still works at that limit although a bit wonky sometimes. The user is actively informed about stability issues when setting more than about 300 LEDs.

Once fully tested, I will push an update to this PR

@DedeHai DedeHai marked this pull request as draft September 18, 2025 05:58
@willmmiles
Copy link
Member

@willmmiles IMO there is no need to complicate things with bus placeholder. The only thing needed to be done is ignore isOk() on some places and proceed without memory allocation and underlying physical bus initialisation.

I considered that approach, but it would mean that all bus types would need have to have a "don't actually construct" argument, which struck me as rather silly. I found that using a clearly defined placeholder type was a cleaner implementation in the current code. I agree that there is a general problem of handling bus initialization failure that overlaps quite a bit here, but I think that needs to be approached in context of a bigger Bus API redesign. (I haven't done a full pass over it yet, but I'd like to give serious thought to elimininating IsOk() in calls like setPixelColor() in favor of replacing a failed bus with a Placeholder instead. This should yield a slight speedup as we don't need to run the check for every pixel, it gets embedded in the virtual dispatch instead.)

@willmmiles
Copy link
Member

  • for existing configs that would exceed the limit the bus length gets truncated (thx @willmmiles for taking the effort)

I'm still hard against that. Either construct the bus or don't, but don't change the user's settings.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 18, 2025

I'm still hard against that. Either construct the bus or don't, but don't change the user's settings.

doesn't your added code take care of that? i.e. truncating the created bus but keeping the config? sorry, did not yet have time to study in detail what you added.

edit: the underlaying issue I am trying to address: ESP8266 on 0.16 will have a bad time (to the point where UI access becomes impossible) if you are coming in with a config using >1000 LEDs. Not creating the bus is one option, creating it but smaller would not leave users with a "its all bricked" moment. Not sure how edge-case this is though.

@blazoncek
Copy link
Collaborator

all bus types would need have to have a "don't actually construct"

I don't think so. If they fail to construct properly, they are just not ok.

However, the approach here is that you want to check if memory exceeds MAX_LED_MEMORY before bus is created and it is done in finalizeInit(). If you move the check into BusManager::add() you can summarize existing buses, add estimate of current bus and then decide what to do. This would simplify finalizeInit() function.
I've foreseen expansion of virtual buses (see usermod bus PR) and this could be of such use. Virtual bus that does nothing, but will retain every option selected.

I, personally, would just drop such bus and every bus after it.

@willmmiles
Copy link
Member

The posted code creates a fake bus that holds the settings but is inactive -- it doesn't produce any output. It seemed the best approach to me; making working busses that have different internal sizes than their settings would be complex to say the least.

Re tightened requirements on 0.16, I think we should come at this from two fronts:

  • First, add a check in 0.15.2 that'll refuse the update if your config won't be valid. Implement Metadata-Based OTA Release Compatibility Checking System #4930 puts the framework in place for that -- while the prototype there only checks the release name, we're free to add additional useful information in the metadata struct, such as a "recommended max LEDs" value. I expect this to catch 90-95% of problem cases. Users can still use the "override" flag to force an update, but at that point we're justified in saying "you were warned".
  • Second, if the config is no longer valid in the new version, then we prioritize (a) keeping the web interface up to allow the user to fix the config and/or switch firmware; then (b) making it clear the config is unsupported (for example: if you upload a config with too many LEDs with this PR; then after you reboot, the settings page tells you why it's unhappy right away when you open it). If the user wants to fix their config by lowering the number of LEDs, they're free to do so at that point; but I suspect most such users would rather downgrade than have their configuration changed. As long as the web API stays up, the device isn't "bricked" - it's just not working ;)

@willmmiles
Copy link
Member

all bus types would need have to have a "don't actually construct"

I don't think so. If they fail to construct properly, they are just not ok.

I was trying to make the point that allowing a "bus is not ok" state puts a performance cost on every bus access. If we do not allow "not ok" busses to exist at all -- replacing them with placeholders or the like -- then we don't ever have to check if the bus is ok, speeding up the core render loops.

However, the approach here is that you want to check if memory exceeds MAX_LED_MEMORY before bus is created and it is done in finalizeInit(). If you move the check into BusManager::add() you can summarize existing buses, add estimate of current bus and then decide what to do. This would simplify finalizeInit() function. I've foreseen expansion of virtual buses (see usermod bus PR) and this could be of such use. Virtual bus that does nothing, but will retain every option selected.

I agree that the division of work between finalizeInit() and BusManager isn't in the right place. As usual my predilection for the minimal patch involves extra work to avoid changes to the code structure. I'll see if I can spare another hour to do a better cleanup.

I, personally, would just drop such bus and every bus after it.

We cannot drop busses as it destroys the user configuration. IMO "my configuration didn't save" is always a bug.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 18, 2025

I have a new approach/suggestion whicht might not require to divert or drop any buses but its a bit of a stretch: accept all buses if memory permits (or even if it does not really). Let the heap checker in the main loop handle the rest.
Reasoning: this whole situation only arises if a user
a) upates from a version that is incompatible
b) manually manipulates the config
If the heap-check in the main loop is updated to free as much heap as required (for example by dropping all buses) the UI will still work (after a while) and users are able to update the config.

@willmmiles
Copy link
Member

If the heap-check in the main loop is updated to free as much heap as required (for example by dropping all buses) the UI will still work (after a while) and users are able to update the config.

Unfortunately, if it drops all busses, none of them will appear in the settings page: the bus list there is generated from the live BusManager state.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 19, 2025

If the heap-check in the main loop is updated to free as much heap as required (for example by dropping all buses) the UI will still work (after a while) and users are able to update the config.

Unfortunately, if it drops all busses, none of them will appear in the settings page: the bus list there is generated from the live BusManager state.

since the major change in this matter are the added buffers, simply dropping those should work. The heap checker currently drops all segments but if the culprit is the global _pixels buffer, resetting segments is not enough. Adding a "heap panic" extension to the checker and maybe some function to free that buffer might do the trick without messing with buses.

Edit: this works

    if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) {
      DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap);
      if(heapPanic) {
        DEBUG_PRINTLN(F("!Heap panic reset!"));
        strip.~WS2812FX();      // deallocate strip and all its memory
        new(&strip) WS2812FX(); // re-create strip object, respecting memory limits
      }
      forceReconnect = true;
      strip.resetSegments(); // remove all but one segments from memory
      heapPanic = true;      // enable last resort measures on next call if heap is still low
    } else if (heap < MIN_HEAP_SIZE) {
      DEBUG_PRINTLN(F("Heap low, purging segments."));
      strip.purgeSegments();
    } else {
      heapPanic = false;
    }

Edit2:
I finally get your point about the "dummy bus" to respect the config settings. While I do agree that messing with users setting is bad, truncating a bus wont directly do that unless a user saves them but you are correct that it may be confusing. If we do add stubs, those must be highlighted in settings to indicate so or the next question will be: "why won't LEDs light up?"
To recap:

  • I agree there should be a workaround for setups that now exceed the capabilities
  • I disagree that a bus should just be dropped/duped, leaving users literally "in the dark", capping its length is a better indicator (imagine a ESP8266 with just one output, 900 LEDs)
  • I dont have a good solution to the config issue, I imagine adding a new variable to distinguish configured length and actual length is a bad workaround.

Edit3:
with the above heap guard "fix" we could keep the old bus creation logic, thus any bus that was allowed before will still be allowed. if it breaks the UI, it will recover within a minute and not change any settings. My current code will not let a user save settings that are considered unsafe, so they are left with the choice to update the settings to safe levels or downgrade.

@willmmiles
Copy link
Member

willmmiles commented Sep 20, 2025

  • I disagree that a bus should just be dropped/duped, leaving users literally "in the dark", capping its length is a better indicator (imagine a ESP8266 with just one output, 900 LEDs)
  • I dont have a good solution to the config issue, I imagine adding a new variable to distinguish configured length and actual length is a bad workaround.

Right, I don't think you can have both. Either you seperately store "configured" vs "live" lengths, OR you have to null out buses that can't be allocated. I really don't think we should be trying to support "partially functional" buses. Also, if we override the user config, we open ourselves up to "why doesn't my configuration work??? I saved 900 LEDs but only 30 light up??" if there's ever a bug in the JS validation.

I applaud that you're pushing for graceful degredation. What would change my mind on this is a better solution for posting error messages back to the main UI. Something that would stay on screen (without covering up parts of the interface) and clearly indicate what the system is unhappy about, what recovery actions were taken, and where to go to fix it. Otherwise I think sophisticated recovery behaviour will be more confusing to users than helpful.

Edit3: with the above heap guard "fix" we could keep the old bus creation logic, thus any bus that was allowed before will still be allowed. if it breaks the UI, it will recover within a minute and not change any settings. My current code will not let a user save settings that are considered unsafe, so they are left with the choice to update the settings to safe levels or downgrade.

I'm on board with the heap guard fix, but I do think it's worth pointing out that the impact of it is the same as dropping the bus: the LEDs will stay dark if there isn't enough memory to allocate _pixels or segment buffers.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 20, 2025

The way I see it is once again a question of "how do we anger the least users" :)
Disregarding the general issue about buses that can't be allocated (to which I think your approach is good) it is mostly if not only about ESP8266 with more than 700 LEDs, which we saw might be not that uncommon.
With 0.14 and 4k of LED buffer memory the max should be around 1300 LEDs. Not sure about non WS281x types but I assume those are less common on this ESP. In my current approach (not in this PR) its like this:

  • use the same calculation limit as it was, I tested a bus with 1200 LEDs.
  • At bootup, there is enough heap to allocate this amount, including _pixels[] and segment buffer and the LEDs light up.
  • After wifi connects, heap drops below 6k, bricking the UI
  • When heap recovery kicks in, enough heap is available (almost 10k) and UI starts working
  • LEDs are still on, lit in orange but cant be controlled as there is no segment buffer anymore.
  • Settings show a big red warning that memory is exceeded more than 2 fold.
  • When trying to save, it sais that this many LEDs cant be handled and user has to reduce to about 700LEDs in order to allow saving settings.

what I did not try yet is if the heap is enough to do an OTA downgrade. IMHO this would be a good approach to solve this particular case.
If we say we only allow full functionality or non at all, the new limit for the ESP8266 is around 300 pixels, for ESP32 about 3000, which I personally think a lot of existing setups may exceed thus resulting in lots of complaints. A somewhat functional system (i.e. only one segment layer, not all effects work with transitions, sometimes segments will not get a buffer etc.) but working UI and working in general is limited to approx. 700LEDs on ESP8266 and 4000LEDs on ESP32 (tested).

@willmmiles
Copy link
Member

The way I see it is once again a question of "how do we anger the least users" :)

We're in agreement on that!

  • use the same calculation limit as it was, I tested a bus with 1200 LEDs.
  • At bootup, there is enough heap to allocate this amount, including _pixels[] and segment buffer and the LEDs light up.
  • After wifi connects, heap drops below 6k, bricking the UI
  • When heap recovery kicks in, enough heap is available (almost 10k) and UI starts working
  • LEDs are still on, lit in orange but cant be controlled as there is no segment buffer anymore.
  • Settings show a big red warning that memory is exceeded more than 2 fold.
  • When trying to save, it sais that this many LEDs cant be handled and user has to reduce to about 700LEDs in order to allow saving settings.

I'm worried that seeing it light the LEDs in orange might give the false impression that we're applying some artificial limit in the config page. After all, clearly the software is capable of lighting them up -- so why can't I use them?

Still I think we're largely in agreement in the overall thrust of the solution. Lighting the LEDs or not when under memory pressure is negotiable.

what I did not try yet is if the heap is enough to do an OTA downgrade. IMHO this would be a good approach to solve this particular case.

+1 - we should guarantee that at least.

If we say we only allow full functionality or non at all, the new limit for the ESP8266 is around 300 pixels, for ESP32 about 3000, which I personally think a lot of existing setups may exceed thus resulting in lots of complaints. A somewhat functional system (i.e. only one segment layer, not all effects work with transitions, sometimes segments will not get a buffer etc.) but working UI and working in general is limited to approx. 700LEDs on ESP8266 and 4000LEDs on ESP32 (tested).

I think we should set the "hard" limits where things will work with no layering or transitions. Those are fun features but at least some real-world setups can get by without them. In the code, we should do what we can to degrade gracefully (eg. cancel transitions first if we're out of memory for segments; have a strong and well-documented ordering for discarding segments if there's insufficient memory for all of them; etc.) and provide some guidance on the "definitely safe" limits on the web site.

@willmmiles
Copy link
Member

what I did not try yet is if the heap is enough to do an OTA downgrade. IMHO this would be a good approach to solve this particular case.
+1 - we should guarantee that at least.

Short answer seems to be that this will need work... I wasn't intending to test this, but I ran in to it with #4930 since I was just using the same 8266 I was last testing for this PR, configured for 500 LEDs. It triggered the low heap handler during the upload and reset the wifi. :(

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 21, 2025

how long did that OTA take? I just tested with my enhanced code and OTA works as long as it takes less than 45 seconds. could up that limit easily.

Let me summarize what we discussed and the options as I see them:

  • updates from <0.16 can have more LEDs configured than can safely be handled
  • if there are bugs in 0.16 onward, we want to handle failed buses more gracefully: currently, they are dropped and no longer show on the config page but still remain in the config file. Suggestion by @willmmiles is to create "dummy" buses as placeholders. These should be rare cases, I agree with this handling.
  • mostly (only?) relevant for 8266 setups with > 700 LEDs configured: after updating, we have these options to handle it:
    • let bus creation fail silently, probably leaving users puzzled as why nothing works, settings will show the bus removed
    • defer bus creation to a dummy, leaving settings page intact. Settings page does inform about excessive memory use but LEDs wont do anything and cant be controlled, also leaving users puzzled.
    • truncate the bus to 30 LEDs showing at least some effort, config will show a 30LED bus. If users hit save, it will overwrite the config and they have to set that up again after downgrading. less puzzling but probably more annoying.
    • accept the way too large bus (works after the OTA reboot) leaving no heap to load the UI, i.e. its bricked until the heap-guard kicks in and drops the buffers after 30 seconds (tested and working). This may also leave users puzzled as "it works for a few seconds" but then stops doing so. The config page will show correct bus(es) warning is present.
  • In all cases, saving LED settings is denied until reasonable values are entered (about 700 LEDs currently)

To me, any of the options are possible, personally I think the last one might be the least disruptive but would collide with the dummy approach which has other benefits in the future (no isOK() checking). I do agree here that users need more info on what is going on. We could add a slightly more sophisticated "error" log. Instead of doing the current short "toast" message, an error / symbol could be added to the UI, if clicked, it opens an error log of the last x error messages that could be a bit more descriptive. Extending the ERR_x list in const.h is possible.

@willmmiles
Copy link
Member

willmmiles commented Sep 21, 2025

how long did that OTA take? I just tested with my enhanced code and OTA works as long as it takes less than 45 seconds. could up that limit easily.

I didn't time it; I had a bunch of extra serial logging enabled to track the validation process as the ESP8266 validation has to be done partway through the upload. It wasn't super fast but I doubt it was a full 45 seconds. In any event, I'm not ok with "fails if your wifi isn't fast enough". Using lots of memory during OTA is normal and expected -- that's why it clears all the segments first. I'll figure out a way to cue the heap recovery to please leave the wifi alone if an OTA is in progress, and ensure the OTA failure timeouts are short enough that it'll recover quickly if there's a real problem with the OTA itself. (One of the fixes in the WIP patch is to guarantee that regular processing is restarted if the OTA aborts halfway - the original code wouldn't always recover.)

  1. let bus creation fail silently, probably leaving users puzzled as why nothing works, settings will show the bus removed
  2. defer bus creation to a dummy, leaving settings page intact. Settings page does inform about excessive memory use but LEDs wont do anything and cant be controlled, also leaving users puzzled.
  3. truncate the bus to 30 LEDs showing at least some effort, config will show a 30LED bus. If users hit save, it will overwrite the config and they have to set that up again after downgrading. less puzzling but probably more annoying.
  4. accept the way too large bus (works after the OTA reboot) leaving no heap to load the UI, i.e. its bricked until the heap-guard kicks in and drops the buffers after 30 seconds (tested and working). This may also leave users puzzled as "it works for a few seconds" but then stops doing so. The config page will show correct bus(es) warning is present.

In all cases, saving LED settings is denied until reasonable values are entered (about 700 LEDs currently)

(edited to add numbers)

My preference order would be 2, then 4; I still think "doesn't work at all" is a clearer indication that the configuration is untenable than "seems to work. then stops". I don't think 1 or 3 are good plans; anything that overwrites the user config is bad. (I for one don't usually remember the exact count of LEDs in a particular build - if I don't remember to back up the config, I end up doing "does 320 light them all? No? How about 350? OK, maybe 335?")

I'd also note that 4 needs a fallback to 2 if even the bus creation fails (ie. someone uploads a bad backup file that has so many LEDs that we can't even construct the buses and buffers once). Ultimately at the code level the difference between the two is only "what is the hard limit at bus creation time" -- the code itself between 2 and 4 should otherwise be identical.

(Or to put it another way, I think your improvements to the heap recovery are a good idea regardless of what we do for bad config handling.)

I do agree here that users need more info on what is going on. We could add a slightly more sophisticated "error" log. Instead of doing the current short "toast" message, an error / symbol could be added to the UI, if clicked, it opens an error log of the last x error messages that could be a bit more descriptive. Extending the ERR_x list in const.h is possible.

We should probably open a separate issue for an improved error UI and sort out the details elsewhere.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 21, 2025

In any event, I'm not ok with "fails if your wifi isn't fast enough".

fully agreed, the heap recovery needs a "gate". I don't know enough about the OTA handler, it might have "is in progress" check.

My preference order would be 2, then 4; I still think "doesn't work at all" is a clearer indication that the configuration is untenable than "seems to work. then stops".

you guess is as good as mine :) I have no strong preference, users might have.

I'd also note that 4 needs a fallback to 2 if even the bus creation fails

absolutely. I did not poke at "bugged" cases, just the real set limits. And also some UM's might hog a ton of static memory or heap which we cannot anticipate.

Ultimately at the code level the difference between the two is only "what is the hard limit at bus creation time" -- the code itself between 2 and 4 should otherwise be identical.

correct.

We should probably open a separate issue for an improved error UI and sort out the details elsewhere.

right.

So I think we are in agreement. Shall I go ahead an merge my local changes to this PR? that would be:

  • changes to LED setup to enforce some limits
  • remove the 30 LED limit, as well as any restricting memory limit but keep the "dummy" fallback if a bus fails anyway (case 2 + 4)
  • add my improvements to the heap handler
  • any other minor changes

in order for these changes to effective, #4928 should be merged first. We can still adjust that PR later if there are any bugs in it, they just need to be added to the 0.15 version PR as well.

@willmmiles
Copy link
Member

I've put a review on #4928. After those fixes, yes please go ahead and merge your updates here!

@DedeHai DedeHai marked this pull request as ready for review September 28, 2025 09:29
coderabbitai[bot]

This comment was marked as resolved.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 28, 2025

@willmmiles I added in my improvements to the low-heap handler in main loop.
also added disableForceReconnect which is enabled during OTA. it does not have a timout so if OTA gets interrupted due to network error, I think it wont reach the cleanup stage and stays disabled (and strip stays suspended, as it was, IMHO an edge case with no horrible consequences).
Also added a isPlacehoder() to the bus: could also use isOK() but I thought this might have some future benefit, can remove later if it turns out that its not useful.
from my side this is ready to merge, I have some more heap handling improvements I did not want to add to this PR which fix some issues on ESP8266.
I think this is a good base to refine the bus management, still needs more work to come to a conclusion on how to handle bus & buffer memory as MAX_LED_MEMORY currently serves double-duty: once for bus allocation and once for UI memory limits. In UI, required buffers are included but MAX_LED_MEMORY is doubled as buffers should respect min heap whereas busses do not (and currently can't as they use constructors and not the malloc_x() functions)

@willmmiles
Copy link
Member

also added disableForceReconnect which is enabled during OTA. it does not have a timout so if OTA gets interrupted due to network error, I think it wont reach the cleanup stage and stays disabled (and strip stays suspended, as it was, IMHO an edge case with no horrible consequences).

I fixed the update cleanup handling in #4960, it'll run no matter why the update failed. (Although deleting the segments to free RAM is, alas, currently unrecoverable.) I'd also added an "update in progress" test to the heap check -- I went the other way and had the heap checker inspect the Update state directly so it'd work with ArduinoOTA or other non-HTTP implementations. (Although such backdoors will also skip the suspend() and the #4960 validation, sadly. :( )

Merge conflicts, here we come... ;)

Also added a isPlacehoder() to the bus: could also use isOK() but I thought this might have some future benefit, can remove later if it turns out that its not useful.

Ultimately I want to go the other way around -- I don't think we should ever have any isSomeBusType() calls. The Bus abstraction ought to be actually properly abstract over the needs of Bus clients -- that needs to be a goal of the Bus API improvements.

I think this is a good base to refine the bus management, still needs more work to come to a conclusion on how to handle bus & buffer memory as MAX_LED_MEMORY currently serves double-duty: once for bus allocation and once for UI memory limits. In UI, required buffers are included but MAX_LED_MEMORY is doubled as buffers should respect min heap whereas busses do not (and currently can't as they use constructors and not the malloc_x() functions)

Agreed. Personally I'd also like to clean up the duplication of the memory estimation code in C++ and JS. Later I think we should add an HTTP API endpoint for letting the JS call the C++ code to do the memory estimation. Hopefully should be straightforward after the bus management work is done.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 28, 2025

I'd also added an "update in progress" test to the heap check
Merge conflicts, here we come... ;)

much better way of doing it. I will remove my crude "hold up with that reset" for one less conflict ;)

Also added a isPlacehoder() to the bus: could also use isOK() but I thought this might have some future benefit, can remove later if it turns out that its not useful.

Ultimately I want to go the other way around -- I don't think we should ever have any isSomeBusType() calls. The Bus abstraction ought to be actually properly abstract over the needs of Bus clients -- that needs to be a goal of the Bus API improvements.

sounds like a good goal. I will leave the check in for now.

Agreed. Personally I'd also like to clean up the duplication of the memory estimation code in C++ and JS. Later I think we should add an HTTP API endpoint for letting the JS call the C++ code to do the memory estimation. Hopefully should be straightforward after the bus management work is done.

Fully agree. I also thought about that but could not come up with a good plan on how to do it, my JS / HTTP / WS knowledge is very limited.

So is this good to merge after I remove the connection reset blocker mentioned above?

@willmmiles
Copy link
Member

So is this good to merge after I remove the connection reset blocker mentioned above?

I haven't been able to do a thorough review or test it, but the overall approach seems OK.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Sep 28, 2025

no problem, I'll wait with merging until you approve.

coderabbitai[bot]

This comment was marked as resolved.

- reverting changes as they are related to parallel loading, I have found a better way to only use sequential loading which makes these changes obsolete
@DedeHai DedeHai changed the title Safety Checks for UI, fix for cfg exceeding LED limit Fix for cfg exceeding LED limit Oct 17, 2025
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.

No fallback if bus fails to be added in 0.16

3 participants