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

    • Graceful handling when LED memory/channel limits are exceeded: continues with placeholders instead of failing, with clearer error reporting.
    • Staged low‑memory protection: progressively simplifies effects, recreates segments, and can fully reset LED strips to maintain stability.
  • Bug Fixes

    • Prevented UI crashes when LED metadata or elements are missing by adding safe defaults and checks.
    • Ensures a default segment is recreated if segments are lost due to low memory.
    • More robust segment power/length handling in the UI to avoid undefined access errors.

- 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

Introduces BusPlaceholder and updates BusManager::add signature. Adjusts WS2812FX initialization to add placeholder buses on memory overrun and continue setup. Relaxes isOk() gating in several iterations. Adds UI guards for missing LED info. Expands heap monitoring with staged recovery actions. Updates serialization and JS generation loops.

Changes

Cohort / File(s) Summary of changes
WS2812FX init and segments
wled00/FX_fcn.cpp
finalizeInit iterates bus configs by value, computes memory per bus, adds placeholder buses when memory exceeds MAX_LED_MEMORY, updates length/white-channel/off-refresh, begins buses, applies brightness, initializes ABL, clears configs, updates Segment::maxWidth. Ensures default segment on reset when none exist; adjusts auto-segmentation loop to stop only on null bus.
Bus manager and placeholder support
wled00/bus_manager.h, wled00/bus_manager.cpp
Adds BusPlaceholder class (no-op bus exposing config/pins). Changes BusManager::add signature to add(const BusConfig&, bool placeholder) and constructs BusPlaceholder when requested/over-limit. getLength now returns _len regardless of isOk(). Guards on() and initializeABL() to consider only isOk() digital buses. Exposes placeholder getters and pins retrieval.
Heap monitoring and staged recovery
wled00/wled.cpp
Reworks periodic heap checks with per-second cadence and heapDanger counter. Uses arch-specific free-heap APIs. Adds staged actions at 15/30/45 consecutive low-heap seconds: purge segments and modes, reset segments, then full strip reset and WiFi reconnect. Sets ERR_NORAM at each stage.
Config and settings serialization loops
wled00/cfg.cpp, wled00/xml.cpp
Bus iteration now breaks only on null bus, removing isOk() gate for serialization and settings JS generation.
Web UI robustness
wled00/data/index.js
Adds guards for missing i.leds.count and i.leds.maxseg with defaults and console warnings. Protects DOM accesses in populateSegments, rptSeg, and setSegPwr with existence checks to avoid runtime errors.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • willmmiles
  • blazoncek

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning In addition to the UI safety and bus fallback logic tied to issue #4936, the pull request also modifies the heap checker cadence and introduces a Wi-Fi reinitialization guard for OTA, which fall outside the original scope of providing a bus fallback and UI error handling. Consider splitting the heap management and OTA Wi-Fi reinitialization enhancements into a separate pull request or linking them to their own issue to keep this PR focused on the bus fallback and UI safety objectives.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly highlights the two core changes—adding UI safety checks and addressing configurations that exceed LED memory—directly reflecting the primary objectives of the pull request without extraneous detail. It is clear, specific, and concise.
Linked Issues Check ✅ Passed The changes fully implement the linked issue’s requirements by introducing a BusPlaceholder fallback to retain user configurations when LED memory limits are exceeded and by adding defensive guards in the UI code to handle missing JSON elements gracefully, ensuring both device usability and UI robustness as specified in issue #4936.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

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