Skip to content

Set rolling codes only on the main loop; default a set-favorite tilt to the favorite tilt - #37

Merged
cjkas merged 2 commits into
mainfrom
fix/set-my-tilt-rolling-codes
Oct 15, 2026
Merged

cjkas merged 2 commits into
mainfrom
fix/set-my-tilt-rolling-codes

Conversation

@cjkas

@cjkas cjkas commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Summary

Two fixes from docs/KNOWN_ISSUES.md.

Rolling codes are only set by loop(). Sending a command reads, queues and commits a remote's rolling code on loop(). Three web handlers wrote the same codes from the web server task:

 loop()                                async_tcp
   peekNextRollingCode()
-                                        /setRollingCode → setRollingCode(new)
   submitTx(frame)
   commitRollingCode(next)               // the code just set is lost
+
+ /setRollingCode, /restore, /updateShadeConfig
+   → web command queue → loop()
  • A restore could also save an older code to NVS than the one a command had just committed, and that code survived the reboot.
  • These commands never go on air, so they are never held back or refused while the radio is busy (webCommandUsesRadio).
  • The /setRollingCode response reports the new code, as unpair already reports paired:false.
  • /restore now answers after queueing. Malformed options used to send a 500 after the 200 had already gone out.

Set-favorite tilt default.

 /setMyPosition without a tilt
-  tilt = myPos                     // the lift favorite, in stored positions
+  tilt = requestedFavoriteTilt()   // the favorite tilt, as displayed

The old default also flipped twice on a shade with flipPosition. Home Assistant never calls /setMyPosition, and the web UI always sends a tilt.

Evidence

  • Before: /setMyPosition without a tilt on a tilt shade with lift favorite 60 and tilt favorite 70 → tilt favorite set to 60.
    After: test_motion:

    requestedFavoriteTilt(-1, tiltmotor, myTiltPos 70, flip off) → 70
    requestedFavoriteTilt(-1, tiltmotor, myTiltPos 70, flip on)  → 30
    requestedFavoriteTilt(-1, integrated, no favorite)           → -1
    requestedFavoriteTilt(25, none, ...)                         → -1
    
  • test_webcmd: set_rolling_code, restore_shades and load_shades stay off the radio and are never held, even while it is suspended or full.

  • pio test -e native: 222 → 226 test cases, all passing.

  • Flash, esp32devdbg: 1,545,717 → 1,546,405 bytes.

  • Builds locally: esp32devdbg, esp32dev, esp32c3, esp32s3. esp32c6 is left to CI.

  • Hardware (not yet done):

    • Set a shade's rolling code in the web UI, then send a command; the motor responds
    • Restore a backup; the device reboots with the shades restored
    • /setMyPosition with and without tilt on a tilt shade

Merge Danger

Door: two-way

No stored formats or API routes change.

Blast Radius: API

  • /setRollingCode applies on the next loop() pass instead of before the response.
  • /setRollingCode and /restore answer 503 when the web command queue is full. /updateShadeConfig can't answer from its upload handler, so a full queue only logs and drops the upload.
  • A restore now runs on loop(), which is busy reading the file for that moment. The device still reboots 1 s later.
  • API callers that leave tilt out of /setMyPosition now keep the favorite tilt instead of getting the lift favorite.

🤖 Generated with Claude Code

cjkas and others added 2 commits October 14, 2026 15:57
/setMyPosition filled in a missing tilt with the lift favorite, so a
request without a tilt set the favorite tilt to the lift's. It also took
the stored position as a display one, which flipped it twice on a shade
with flipPosition. requestedFavoriteTilt() now gives the favorite tilt as
displayed. Home Assistant never calls /setMyPosition and the web UI always
sends a tilt, so only other API callers see the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sending a command reads a remote's next rolling code, queues the frame and
commits the code, all on loop(). /setRollingCode, a shades restore and
/updateShadeConfig wrote the same codes from the web server task, so a set
could be undone by a command's commit, and a restore could save an older
code to NVS that survived the reboot. All three now go through the web
command queue to loop(). They don't use the radio, so they are never held
back or refused while it is busy.

/restore now answers after queueing the restore. A broken options string
used to send an error after the success answer had already gone out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cjkas
cjkas merged commit 7396786 into main Oct 15, 2026
5 checks passed
@cjkas
cjkas deleted the fix/set-my-tilt-rolling-codes branch October 18, 2026 11:31
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.

1 participant