Skip to content

fix: skip cached state override when plug/humidifier ignore command#503

Draft
bluetoothbot wants to merge 2 commits into
sblibs:masterfrom
bluetoothbot:koan/plug-humidifier-state-gate
Draft

fix: skip cached state override when plug/humidifier ignore command#503
bluetoothbot wants to merge 2 commits into
sblibs:masterfrom
bluetoothbot:koan/plug-humidifier-state-gate

Conversation

@bluetoothbot
Copy link
Copy Markdown
Collaborator

@bluetoothbot bluetoothbot commented May 19, 2026

What

Gate _override_state on the result of _check_command_result in SwitchbotPlugMini.turn_on/turn_off and SwitchbotHumidifier._async_set_state/_set_level. Same shape as #502 (bot), extended to the other two device classes where the existing _check_command_result call was discarded.

Why

Audit follow-up to #502 (which fixed the bot half of #213). The same anti-pattern lives in plug.py and humidifier.py:

ret = self._check_command_result(result, 1, {0x80})  # protocol says "accepted?"
self._override_state({"isOn": True})                  # …but we override anyway

If the device returns anything other than the expected ACK byte, ret is False but the cached state still gets flipped, so the library lies about state to its caller. The bot version was observed in the wild (#213); the plug/humidifier versions are the same code shape and the existing _check_command_result calls show the original author already intended to validate — the gate was simply missing.

How

Two-line gate in each method, matching #502:

ret = self._check_command_result(result, ...)
if ret:
    self._override_state({...})
    self._fire_callbacks()
return ret

Behaviour for the accepted path is unchanged.

Testing

  • New tests/test_plug.py (4 tests): accepted/rejected × turn_on/turn_off.
  • New tests/test_humidifier.py (6 tests): accepted/rejected × turn_on/turn_off/set_level. Neither device had a test module before.
  • Full suite: 1223 passed.

🤖 Generated with Claude Code


Quality Report

Changes: 4 files changed, 201 insertions(+), 8 deletions(-)

Code scan: clean

Tests: passed (1223 passed)

Branch hygiene: clean

Generated by Kōan post-mission quality pipeline

bluetoothbot and others added 2 commits May 19, 2026 19:35
Extends the bot fix from sblibs#502 to SwitchbotPlugMini and SwitchbotHumidifier:
both `turn_on`/`turn_off` (and humidifier's `set_level`) ran
`_override_state` unconditionally, even when `_check_command_result`
returned False. A rejected/garbled command response would still flip
the cached state, making HA report a state the device never reached.

Gate `_override_state` and `_fire_callbacks` on the result, matching the
original intent of the existing `_check_command_result` calls.

Tests added: tests/test_plug.py (4 cases), tests/test_humidifier.py (6
cases) covering accepted/rejected paths for turn_on, turn_off, and
set_level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
switchbot/devices/humidifier.py 89.65% <100.00%> (+46.79%) ⬆️
switchbot/devices/plug.py 92.30% <100.00%> (+46.47%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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