Conversation
…transition
deserializeState() flagged stateChanged whenever bri != briOld, before
checking whether the request actually carried "bri". briOld is the
origin of an in-flight brightness transition and differs from bri for
the whole transition, so any POST to /json/state arriving in that window
(e.g. {"ps":N} for the already active preset, which skips applyPreset()
and falls through) reached stateUpdated() and zeroed currentPreset,
reported as "ps":-1.
Compare against the value bri had at the start of the request instead.
A JSON "bri" change still marks the state as changed; only the false
positive from an unrelated transition (WiZmote/IR/button/HTTP A=
brightness steps) is removed.
Introduced by ee9ac94. Reproduced and fix verified on 16.0.1 on an
ESP32-D0WD-V3 with a WiZmote and Home Assistant selecting the active
preset.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. Walkthrough
ChangesBrightness state-change detection
Priority: ➖ Normal Estimated code review effort: 1 (Trivial) | ~5 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to Unrelated requests no longer clear the active preset during a brightness transition; no actionable merge risk remains. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
|
good call, but please remove the lengthy AI comment |
Done in 3ef4ab1 |
What's wrong
Any JSON API request that goes through
deserializeState()while a brightness transition is in progress gets flagged as a state change, even if the request doesn't containbrior change anything at all. That clearscurrentPreset, so the device reportsps: -1and the preset shows as "none" in the UI and as "unknown" in Home Assistant.The cause is this line near the top of
deserializeState():briOldisn't the previous brightness in the sense this line assumes. It's the starting point of the current fade, and it only catches up tobriwhen the transition finishes inapplyFinalBri(). So for the entire transition duration after any brightness change,bri != briOldis true regardless of what the request contains.stateChangedthen gets set,stateUpdated()runs at the end ofdeserializeState(), and its first act on a changed state iscurrentPreset = 0.The clearest case is
{"ps":N}where N is already the active preset. That request skips the reload (becausepresetCycCurr == currentPreset) and falls through to the end of the function, where the bogusstateChangedclears the preset. But an empty{}or{"v":true}does the same thing during a fade. Requests for a different preset aren't affected, since a real preset load setscurrentPresetagain afterward.This line isn't in 0.15.x (
v0.15.0just hasgetVal(root["bri"], &bri);), so it's a regression in 16.x. It was introduced in ee9ac94 (Segment layering & effect blending improvements, Apr 2025) and is still present onmain.How I ran into it
I have a WLED strip controlled by Home Assistant with a WiZmote paired as a physical remote. One night someone pressed brightness-up on the remote right as an HA automation re-selected the preset that was already active. Remote brightness presses don't touch
stateChanged, so on their own they leave the preset alone, and re-selecting the active preset on its own does nothing either. But the automation's request landed inside the 2 s fade from the button press, and the preset went to -1. Took a while to figure out because neither input reproduces it alone.Reproduce
Any preset active. With the default 0.7 s transition the window is short, so set the transition to 2 s or more in LED settings first. Use the HTTP API for the brightness change because it doesn't set
stateChanged(same as a remote or button press):Pick an
A=value different from the current brightness, otherwise no transition starts. Run the second command within the transition time and you get"ps":-1. Wait longer than the transition and you get"ps":4. Replacing the{"ps":4,...}body with{}or{"v":true}during the fade also returns -1. A long transition time makes it trivial to hit by hand.The fix
Compare against the brightness the request started with, not against
briOld:Now
stateChangedis only set when the request itself changedbri. A request that actually carries a new brightness still behaves exactly as before, including clearing the preset. Only the false positive during a transition goes away.An alternative would be to only set the flag when
root["bri"]is present. I went with the value comparison because it also avoids flagging a request that setsbrito the value it already has, but I'm happy to change it if the other form is preferred.Tested
Built from the
v16.0.1tag with theesp32devenv and flashed to an ESP32-D0WD (140 px WS2811, AudioReactive included). Before the patch, the reproduction above returned -1 every time. After, it returns the active preset every time, both with the curl commands and with the actual remote plus a Home Assistant preset select. Brightness changes via JSON, on/off, preset loads, and the remote all behave the same as before.Since this is a 16.x regression verified on 16.0.1, it would be good to backport to
16_x.Summary by CodeRabbit