Skip to content

fix: make remote soft wake idempotent#83

Open
ODevStudio wants to merge 1 commit into
mainfrom
odev/fix-idempotent-soft-wake
Open

fix: make remote soft wake idempotent#83
ODevStudio wants to merge 1 commit into
mainfrom
odev/fix-idempotent-soft-wake

Conversation

@ODevStudio

@ODevStudio ODevStudio commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the brief 0.0g weight blip seen after v3.1.12 when a BLE or WiFi client repeatedly sends a wake / soft-sleep-off command while the scale is already awake.

Why It Happens

v3.1.12 added ADS1232 recovery on real soft-sleep wake so the scale does not stay stale or stuck after the ADC power rail comes back. That was correct for an actual transition from sleep to awake.

The Decent BLE command 030A04 00 is also sent by clients as a keep-awake style command. In v3.1.11, duplicate wake commands only turned the display / power rails on, so they did not affect the current weight. In v3.1.12, the same duplicate command went through wakeScaleFromSoftSleep(), which calls scale.powerUp(), refreshes the ADS dataset, and resets the public displayed weight. That left a short window where BLE / WiFi could report 0.0g before the next ADC sample restored the real weight.

What This Fixes

Wake commands are now idempotent:

  • If b_softSleep is true, this is a real wake and the ADS wake / refresh path still runs.
  • If b_softSleep is false, the scale is already awake, so duplicate wake commands only restore the display state and do not refresh/reset the ADS output.

The fix covers BLE, /snapshot WebSocket, and USB command paths so the same protocol behavior stays consistent across transports.

Validation

  • python tools\test_soft_sleep_ads_wake.py
  • rtk proxy pio run -e esp32s3
  • Flashed the patched firmware to COM6.
  • WiFi /snapshot smoke: real soft_sleep on / soft_sleep off still works.
  • Duplicate WiFi soft_sleep off no longer logs remote soft wake dataset refreshed, confirming the ADS refresh path is skipped while already awake.
  • BLE manual reconnect smoke

@ODevStudio ODevStudio marked this pull request as ready for review July 6, 2026 12:50

@tadelv tadelv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve. The threading footgun (#1) is respected: the WS handler (AsyncTCP task) and BLE handler (BLE host task) defer via wsReplacePending/remoteReplacePending and never call wakeScaleFromSoftSleep/scale.powerUp()/digitalWrite(PWR_CTRL,…)/u8g2.setPowerSave directly — everything drains from processWsPendingCmds on loop(). The USB path runs on the loop task, so its direct hw calls are safe there. Mirrors the existing button-wake idempotency guard. b_softSleep/b_u8g2Sleep are volatile. Consistent guard across all three transports. Correctly fixes the v3.1.12 0.0g blip.

Minor (non-blocking):

  • WS/BLE else-branch doesn't clear WSP_SLEEP_ON. The real-wake branch does wsReplacePending(WSP_SLEEP_OFF, WSP_SLEEP_ON) (clears a concurrent sleep-on); the else-branch does wsReplacePending(WSP_DISPLAY_ON, WSP_DISPLAY_OFF) which leaves a concurrently-queued SLEEP_ON alive. Very narrow race and low impact, but for symmetry consider wsReplacePending(WSP_DISPLAY_ON, WSP_DISPLAY_OFF | WSP_SLEEP_ON).
  • The test is static source-shape (ordered snippet matching), not runtime — fine as a contract guard, just be honest that it doesn't exercise the duplicate-while-awake path.

Suggestion (separate from this PR): same note as on #81 — these contract tests grep source structure rather than run the logic. Pulling the wake/state-machine into a pure, host-compilable unit and asserting real behavior (no hardware) would be stronger and would let the firmware logic be tested independently of the device.

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.

2 participants