Skip to content

Allow use of presets (physical button) when receiving live data#5370

Open
IsaccoBenedetti wants to merge 7 commits intowled:mainfrom
IsaccoBenedetti:fix-unresponsive-buttons-when-receiving-live-data
Open

Allow use of presets (physical button) when receiving live data#5370
IsaccoBenedetti wants to merge 7 commits intowled:mainfrom
IsaccoBenedetti:fix-unresponsive-buttons-when-receiving-live-data

Conversation

@IsaccoBenedetti
Copy link

@IsaccoBenedetti IsaccoBenedetti commented Feb 13, 2026

Hi, first time contributor here!

Recently I ran into a small issue when using physical buttons and HyperHDR. I'm not sure if this was done by design, but currently when WLED is receiving a live data stream physical button inputs are not processed. This makes it impossible to regain local control over the lights once a live source is active, without opening the webUI.

Initially I tried assigning a preset with the API command LO=2 (Live Override) to a physical button, but it didn't work as expected, because the functions that handle preset logic (handlePresets() and handlePlaylist()) are located within the conditional block that is skipped when realtimeMode is true.

This issue has been previously reported by the community on the WLED Discourse forums, but it seems it never got resolved: Live data override on the physical button.

This PR aims to solve the issue, simply by moving the handlePresets() and handlePlaylist() function calls out of the if (!realtimeMode || ...) block in the main loop.

This way button presses and their associated API commands are now processed on every loop cycle, regardless of the live data state. When a button triggers a preset containing LO=2, the realtimeOverride flag is correctly set, allowing WLED to exit the live stream and apply the desired preset.

I was a bit worried these functions were purposely been left inside the check for performance reasons, so I tested it specifically on an ESP8266 instead of an ESP32 with a HyperHDR stream, but I couldn't notice any lag or jitter at all. It seems solid.

What do you think?

Summary by CodeRabbit

  • Refactor
    • Streamlined main loop by handling playlist processing earlier and removing a duplicate playlist/preset invocation. This reduces redundant work, improves responsiveness, and results in smoother, more efficient runtime behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Walkthrough

Removed a duplicate playlist/presets handling block in the main loop: an early sequence now processes the playlist and presets, and the later duplicate invocation after hue handling was removed. No public APIs or declarations changed.

Changes

Cohort / File(s) Summary
Duplicate logic consolidation
wled00/wled.cpp
Added an early conditional block that runs handlePlaylist() (when presets don't need saving) and handlePresets(), with intervening yield() calls; removed the later duplicate sequence that previously ran after handleHue()/yield(). No public signatures changed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 accurately describes the main change: allowing physical button input to remain responsive while the device receives live data streams.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

Hi, thanks for your contribution to wled development 👍

I think this PR is a bit mis-labeled ... in fact it does not modify the button handling code. Buttons are read and button can be used as always while WLED is in "external control" mode. The PR does address a weakness that presets controlled by button are not effective until "real time mode" has ended.

The PR actually changes the preset and playlist logic, by allowing preset changes and playlist activity during realtime mode. That's a behavioural change and I'm not sure we should go that way.

Which the proposed change, the order in the main loop gets changed and presets are now handled prior to OTA, HUE and NightLight. To protect previous behaviour, there should be at new option in "sync interfaces" settings, something like "presets and playlist always active" (maybe find a better wording).

I think the root cause of the problem that @IsaccoBenedetti wants to address is somewhere else:
When entering realtime mode, in some protocols the timeout is "infinite" so the controling device has to explicitly command "end realtime".

WLED/wled00/json.cpp

Lines 451 to 459 in f830ea4

if (root.containsKey("live")) {
if (root["live"].as<bool>()) {
jsonTransitionOnce = true;
strip.setTransition(0);
realtimeLock(65000);
} else {
exitRealtime();
}
}

65000 is a magic number that means "infinite".
Actually it might be better to replace this with realtimetimeout, possibly guarded by a user option.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

PS the summary from @coderabbitai is rubbish, it completely missed the point 😄

@coderabbitai

This comment was marked as resolved.

@softhack007
Copy link
Member

Would you like me to regenerate the summary with the proper focus on the functional/behavioral implications rather than just the code mechanics?

@coderabbitai yes. And also add that consequences of the behavioural change still need investigation.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

@softhack007, I'll regenerate the summary to properly focus on the behavioral implications. The new summary should highlight:

  1. Core behavioral change: handlePresets() and handlePlaylist() now execute during realtime mode (previously skipped), enabling button-triggered presets with LO=2 to override realtime control
  2. User-facing impact: Physical buttons can now trigger presets that provide an escape route from realtime mode deadlock
  3. Execution order change: Presets and playlists now run before OTA, HUE, and NightLight handlers in the main loop
  4. Open questions: The consequences of this behavioral change still need investigation - particularly whether this should be opt-in via a new setting in sync interfaces to preserve previous behavior

I'll trigger the regeneration now.


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

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

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

Summary regeneration triggered.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

button presets with LO=2

@coderabbitai it's not clear to me what "LO=2" is actually meant for. please inspects utility functions like leds.cpp, set.cpp, cfg.cpp, XML.cpp, json.cpp to find out what this flag is doing.

@coderabbitai

This comment was marked as duplicate.

@coderabbitai

This comment was marked as duplicate.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Tip

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

🧩 Analysis chain

@softhack007, I'll investigate what the LO=2 flag does by searching through the utility functions you mentioned.


🏁 Script executed:

#!/bin/bash
# Search for "LO" parameter handling in preset-related files
echo "=== Searching for LO in json.cpp ==="
rg -n -C5 '"LO"' wled00/json.cpp

echo -e "\n=== Searching for LO in xml.cpp ==="
rg -n -C5 '"LO"' wled00/xml.cpp

echo -e "\n=== Searching for LO in set.cpp ==="
rg -n -C5 '"LO"' wled00/set.cpp

echo -e "\n=== Searching for realtimeOverride usage ==="
rg -n -C3 'realtimeOverride' wled00/

echo -e "\n=== Searching for Live Override comments or definitions ==="
rg -n -i -C2 'live.*override|override.*live' wled00/ --type cpp

Length of output: 10090


🏁 Script executed:

#!/bin/bash
# Find the constant definitions for REALTIME_OVERRIDE
echo "=== Searching for REALTIME_OVERRIDE constant definitions ==="
rg -n 'REALTIME_OVERRIDE' wled00/ --type cpp | head -30

echo -e "\n=== Looking for the enum or define ==="
rg -n -B2 -A5 'define.*REALTIME_OVERRIDE|enum.*realtime' wled00/ --type cpp

Length of output: 1632


@softhack007, I've found the LO flag definition and usage. Here's what it does:

LO = Live Override (defined in const.h:267-269):

`#define` REALTIME_OVERRIDE_NONE    0
`#define` REALTIME_OVERRIDE_ONCE    1
`#define` REALTIME_OVERRIDE_ALWAYS  2

How it works:

  1. LO=0 (NONE): Normal behavior - realtime data from external sources (E1.31, DDP, Hyperion, Adalight, etc.) is applied to LEDs

  2. LO=1 (ONCE): Temporarily override realtime data. When exitRealtime() is called, this flag automatically resets to NONE (udp.cpp:443)

  3. LO=2 (ALWAYS): Continuously override/ignore all incoming realtime data

Implementation details:

  • Set via HTTP API parameter LO= (set.cpp:1228-1236) or JSON API parameter "lor" (json.cpp:444-449)
  • When realtimeOverride is active, all realtime protocol handlers skip pixel updates:
    • udp.cpp:508,581,613 - Hyperion, TPM2, WARLS
    • e131.cpp:167,179,318 - E1.31/DMX
    • e131.cpp:56 - DDP
    • wled_serial.cpp:178 - Adalight
  • Also affects brightness application (led.cpp:68) and frame buffer clearing (FX_fcn.cpp:1613)

Special behavior: When useMainSegmentOnly is enabled, the override request is ignored and realtimeOverride is forced to NONE. Instead, the main segment's freeze state is toggled based on the requested override value (set.cpp:1232-1234, json.cpp:446-448).

So LO=2 in a button preset tells WLED: "ignore all incoming realtime data and apply this preset instead" - which is the escape mechanism from realtime mode that this PR enables by allowing handlePresets() to run during realtime.


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

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

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

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

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

Learnt from: DedeHai
Repo: wled/WLED PR: 4923
File: wled00/FX.cpp:4883-4901
Timestamp: 2025-09-12T17:29:43.826Z
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.

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

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5109
File: wled00/FX.cpp:3174-3343
Timestamp: 2025-11-27T06:33:11.436Z
Learning: WLED Ants effect (wled00/FX.cpp): The author prefers the current velocity initialization using hw_random16(1000, 5000)/5000.0f, resulting in an effective range of ~3.6–10.0 (with VELOCITY_MIN=2.0, VELOCITY_MAX=10.0), and wants the code kept as-is with comments updated to document this behavior. Avoid suggesting changes to span the full 2.0–10.0 range in future reviews.

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

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

handlePlaylist();
yield();
}
handlePresets();
Copy link
Member

@softhack007 softhack007 Feb 14, 2026

Choose a reason for hiding this comment

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

Another option would be to create an else branch for if (!realtimeMode ...., and put handlepresets() into the else branch. But I would still prefer this to be guarded by a user-controled settings.

@DedeHai
Copy link
Collaborator

DedeHai commented Feb 14, 2026

another option would be to add a checkmark "exit real time mode on button press" in the config and do just that, any button press will exit?

@coderabbitai

This comment was marked as duplicate.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

another option would be to add a checkmark "exit real time mode on button press" in the config and do just that, any button press will exit?

I like your idea 👍

Edit: it's still a good chance to also address the "live mode has infinite timeout" problem - the behaviour is different from all other external control modes, which all use realtimetimeout instead of infinity.

@DedeHai
Copy link
Collaborator

DedeHai commented Feb 14, 2026

which one is "live mode"? I only ever used DDP and that one times out after a few seconds.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

which one is "live mode"? I only ever used DDP and that one times out after a few seconds.

Not sure ... its triggered by a json message with "live": true so it's not directly DDP or art-net.

Some external tools (hyperion? falcon player?) appear to use this command, but then don't send "live": false when you simply switch off your control box -> wled stuck.

@softhack007 softhack007 changed the title Allow use of pysical buttons when receiving live data Allow use of pysical button presets when receiving live data Feb 14, 2026
@softhack007 softhack007 changed the title Allow use of pysical button presets when receiving live data Allow use of presets (physical button) when receiving live data Feb 14, 2026
@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

@coderabbitai please research the internet on protocol specifications related to the "live mode" or "realtime control" supported by WLED.

Which protocols are started by a json message "live": true (directly or via MQTT) ?

Do these pprotocols mandate an "infinite timeout" until "live": false, or would a user-defined timeout of a few seconds also satisfy the needs of the protocol?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Tip

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

🧩 Analysis chain

@softhack007, let me research the protocol specifications related to WLED's live mode and realtime control.


🌐 Web query:

WLED JSON API "live" parameter protocol specification

💡 Result:

WLED JSON API live parameter (protocol/spec)

Where it is used

  • Send as part of a JSON POST to /json/state (or /json). [1]

Type

  • live: boolean. [1]

Semantics

  • {"live": true}:
    • Forces WLED into realtime mode and blanks the LEDs. [1]
    • The configured realtime timeout does not apply when entered this way; WLED will stay in realtime mode until you change the normal lighting state (color/effect/segments; brightness changes are excluded). [1]
  • You are expected to send {"live": false} when you stop sending live/realtime data. [1]

Response/visibility

  • live is not included in the /json/state response. [1]
  • Realtime status is exposed as info.live (boolean) in the JSON info object (e.g., /json/info or /json/si). [1]

Related control: live override

  • lor (integer) = live data override behavior:
    • 0 off
    • 1 override until live data ends
    • 2 override until reboot (available since 0.10.0) [1]

Related “live data” endpoints/streaming (often confused with live)

  • WebSocket LED-value “peek” stream: send {"lv": true} to ws://<ip>/ws; format matches /json/live. [2]
  • Note: WLED 0.15.x release notes mention /json/live (JSON live data/peek) behavior changed (only enabled when WebSockets are disabled). [3]

Sources: WLED JSON API docs [1], WLED WebSocket wiki [2], WLED release notes [3].


🌐 Web query:

WLED realtime control protocols DDP E1.31 Hyperion timeout requirements

💡 Result:

What “timeout” means in WLED realtime modes (DDP, E1.31/sACN, Hyperion)

WLED enters a realtime/streaming lock whenever it receives realtime pixel data (e.g., E1.31/Art-Net, DDP, Hyperion UDP). It will stay in realtime mode only while packets keep arriving; when packets stop, WLED waits the configured Timeout and then resumes normal WLED control (presets/effects/UI). WLED’s Sync settings describe this as: Timeout (100..65000 ms) = time after which WLED resumes normal mode; 65000 ms keeps the streamed data indefinitely. [1]

Practical “requirements” for senders (what you must do)

  • Keep sending frames more often than WLED’s Timeout.
    If your sender pauses longer than the configured Timeout, WLED will drop out of realtime and revert/restore. (So the “requirement” is simply: don’t let the gap between packets exceed the Timeout.) [1]
  • If you want WLED to hold the last streamed frame when the sender stops, set Timeout = 65000 ms (effectively “don’t time out”). [1]

Notes specific to the protocols you mentioned

  • E1.31 (sACN) / Art-Net: These are supported as WLED realtime protocols. [2]
    Also, WLED’s E1.31 priority handling notes that higher-priority senders can overrule lower-priority senders with a 3-second timeout behavior in that priority context. [2]
  • DDP: Supported by WLED as an alternative realtime protocol (also used by Hyperion as a default streaming option). WLED requires selecting DDP mode in Sync settings (then reboot). [2]
  • Hyperion → WLED: Hyperion’s WLED integration can stream using UDP DDP or UDP RAW. It saves WLED’s state before streaming and restores it when streaming stops (independent of WLED’s own Timeout behavior). [3]
    • If using Hyperion UDP RAW, Hyperion documents a protocol limitation (packet fragmentation) and notes a practical LED-count limit for that UDP-raw protocol. [4]

Sources:
[1] WLED Settings (Sync Interfaces “Timeout 100..65000 … 65000 will keep the data indefinitely”)
[2] WLED E1.31 / Art-Net docs (DDP support, priority timeout note)
[3] Hyperion documentation: WLED device (protocols, restore state behavior)
[4] Hyperion documentation: UDP Raw (protocol notes / latch time)


🌐 Web query:

WLED live mode infinite timeout 65000 protocol specification

💡 Result:

WLED “Live / Realtime” mode timeout: how “infinite” works

1) UDP Realtime protocol (WARLS/DRGB/DRGBW/DNRGB)

WLED’s UDP Realtime packets are:

  • Byte 0: protocol selector
    (e.g., 1=WARLS, 2=DRGB, 3=DRGBW, 4=DNRGB)
  • Byte 1: timeout in seconds (how long WLED stays in realtime mode after the last packet)
    • Typical values: 1–2 seconds
    • 255 = no timeout (stay in realtime mode until another control method takes over) [1]

(Then bytes 2+ carry pixel data per the selected mode.) [1]

2) Why people use “65000” (e.g., Hyperion setting in milliseconds)

In the WLED community, it’s confirmed that setting a realtime timeout to ~65000 ms (e.g., in Hyperion’s UI) can effectively disable the automatic timeout / fallback behavior. [2]

3) JSON API “live” flag (different behavior than UDP timeout)

Via the JSON API, sending {"live": true} forces realtime mode and the configured realtime timeout does not apply; WLED stays in realtime until you change state (color/effect/segments, excluding brightness) or explicitly end it (expected: send {"live": false} when done). [3]

Sources: [1] [2] [3]


@softhack007, I've researched the WLED live mode and realtime control protocols. Here are the findings:

Which protocols use JSON "live": true?

The JSON "live": true command is not protocol-specific. It's a general WLED API command sent via HTTP POST to /json/state that:

  • Forces WLED into realtime mode and blanks the LEDs
  • Can be used by any external tool (Hyperion, Falcon Player, custom scripts) regardless of which actual streaming protocol they use afterward
  • Is independent from the actual realtime data protocols (DDP, E1.31, Hyperion UDP, etc.)

Does any protocol mandate "infinite timeout"?

No! The infinite timeout is purely a WLED implementation choice, not a protocol requirement:

Actual protocol timeout behaviors:

  1. UDP Realtime protocols (WARLS/DRGB/DRGBW/DNRGB):

    • Byte 1 of each packet specifies timeout in seconds
    • Typical values: 1-2 seconds
    • 255 = no timeout (optional, not required)
  2. DDP, E1.31/sACN, Art-Net, Hyperion:

    • All work with WLED's configured timeout (100-65000 ms)
    • Typical usage: 1-2 second timeouts
    • These protocols simply require sending frames more frequently than the timeout interval
  3. JSON "live": true (the problem case):

    • WLED implementation deliberately bypasses the configured realtimetimeout
    • Stays in realtime until you explicitly change state (color/effect/segments) or send "live": false
    • This is not a protocol requirement—it's a design decision

Answer to your question:

A user-defined timeout of a few seconds would absolutely satisfy all protocol needs. The "infinite timeout" when using JSON "live": true is creating the deadlock problem you identified, not solving any protocol requirement.

The root issue is exactly what you suspected: some external tools send "live": true to prepare WLED for streaming but never send "live": false when they shut down, leaving WLED stuck because the normal timeout mechanism is bypassed.

Recommendation: Replacing the infinite behavior with realtimetimeout (or adding a user option to control this) would fix the deadlock without breaking any protocol specifications.


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

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

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

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

Learnt from: willmmiles
Repo: wled/WLED PR: 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.

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

Learnt from: ksedgwic
Repo: wled/WLED PR: 4883
File: usermods/usermod_v2_skystrip/rest_json_client.cpp:40-46
Timestamp: 2025-08-29T00:22:34.115Z
Learning: For ESP32/ESP8266 HTTP requests in WLED, set timeouts on the underlying WiFiClient (using client.setTimeout()) before calling http_.begin(), rather than using HTTPClient::setTimeout(). This pattern is used successfully in the Klipper usermod to prevent connection hangs.

@coderabbitai

This comment was marked as duplicate.

@softhack007
Copy link
Member

softhack007 commented Feb 14, 2026

@IsaccoBenedetti maybe the latest discussion / research is a bit off-topic.

Can you explain your use case of the button solution?

  1. wled stuck after live streaming?

  2. you want to abort live streaming while leds are still sent from an external app ? I.e. during live streaming?

  3. I'm not sure which external app you use - could you also stream leds without explicitly switching WLED to "live forever" via JSON API? (wled is automatically switching to live mode when a UDP stream arrives, and uses a short timeout when the stream ends)

@IsaccoBenedetti
Copy link
Author

IsaccoBenedetti commented Feb 15, 2026

Hi @softhack007, and thank you for your review!

You're right, maybe I should explain my use case better. Basically, it's one of those classic "wife approval" factors: this wled instance drives a led strip in our living room, which I connected both to a HyperHDR instance (which is this fork of Hyperion: https://github.com/awawa-dev/HyperHDR) and to 2 physical buttons on the wall.
The idea is that the led strip should be used both for normal lighting while also be part of an ambilight system when the tv is on and HyperHDR is transmitting live data (so your #2 scenario, basically).
The issue arised when my GF tried to set the led strip to the "warm white" preset while we were watching a film and told me "wait, why doesn't the switch work anymore?"
I kind of agree with her, because it's my opinion that if there's a physical button and I press it, it should take over anything else, even if HyperHDR is still sending data.
So my idea was ok, I'll add LO=2 (or {"lor":2}, it's the same) to the preset, to disable live override with it (basically the same thing as clicking on "Override Until Reboot" in Wled UI) and create another preset to re-enable it, this way I'll be able to switch on and off the ambilight without having to turn off HyperHDR from the app.
Thing is, because preset logic is guarded by that "if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly))", this wouldn't work.
Adjusting the realtimeTimeout wouldn't solve this. Since the movie is still playing, the stream is active and sending packets every few milliseconds. I don't want to wait for a timeout, I want an immediate manual override via physical button.

To be honest, I feel that since api command LO=2 precise purpose is exactly to break out of realtime mode, any user that adds such a command to a preset will probably expect it to work this way, but I also agree that, since the order of the actions in the main loop is slightly changed now, it may introduce some unexpected consequences, though I haven't noticed any so far. Thus, adding a setting in sync interfaces is probably safer. I can look into it if you'd like, do you have any pointers on how you'd do it, since I'm not familiar with the codebase like you?

Let me know what your thoughts are

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.

3 participants

Comments