Skip to content

fix: OpenAPI fallback, BLE replies, discovery merging, OpenAPI commands and BLE model codes - #344

Merged
donavanbecker merged 1 commit into
latestfrom
fix/deep-dive
Oct 24, 2026
Merged

donavanbecker merged 1 commit into
latestfrom
fix/deep-dive

Conversation

@donavanbecker

Copy link
Copy Markdown
Contributor

Bugs found in a review of the library against pySwitchbot, the SwitchBotAPI-BLE protocol docs and the SwitchBotAPI device pages. Each fix has a test that fails without it.

Transport

  • OpenAPI fallback never ran with default settings. With connection intelligence on (the default), sendCommand only set a fallback when it chose a transport other than the preferred one. A failed BLE command on a BLE-preferring device therefore never reached the API.
  • Status reads on macOS: BLE status, Lock and Bot reads used mac ?? id:<bleId>, which passes an empty-string MAC through. They now use the same address as commands.
  • Circuit breaker: the HALF_OPEN trial limit is now enforced, and the recovery timer no longer keeps the process alive.

BLE replies

  • A reply was accepted or rejected by scanning every byte. Payload such as a 7% battery was read as "password required", and an error reply containing 0x01 anywhere was read as success. Replies are now judged by the status byte (byte 0), as in pySwitchbot and the BLE docs.

Discovery

  • An OpenAPI device was matched to its BLE device by type string only. BLE and the API spell types differently (Meter Plus vs MeterPlus), so the API record was dropped and the device never got API fallback. With two devices of one model, the wrong one could be attached and the other lost. Matching is now by id (the MAC without colons equals the OpenAPI deviceId).
  • Type matching remains only for BLE devices with no MAC (macOS). It compares resolved device classes, and API calls then go to the OpenAPI deviceId via the new DeviceInfo.apiDeviceId.

OpenAPI commands

Device Before After
Blind Tilt turnOn, turnOff, setPosition {position}, plus a second API attempt on failure fullyOpen, closeUp, closeDown, setPosition "down;50", one attempt
Air purifiers setMode "auto", setFanSpeed, setPresetMode setMode {"mode", "fanGear"}
RGBIC Neon Wire Rope Light setColor {red, green, blue} setColor "r:g:b"
Color Bulb setColorTemp "min-max:temp" setColorTemperature temp
Vacuums start {protocolVersion} start, or startClean for S10, S20, K10+ Pro Combo, K11+, K20+ Pro

Also mapped Robot Vacuum Cleaner K20 Plus Pro (previously not created at all), and S1/S1 Plus to the base vacuum class.

BLE model codes

DEVICE_MODEL_MAP is aligned with pySwitchbot's SUPPORTED_TYPES. Several codes named the wrong product: 0x06 Presence Sensor → Leak Detector, y Leak Detector → Keypad, 0x0D Relay Switch 1PM → Lock Lite, 0x07 Humidifier 2 → (Universal Remote, unsupported). Many products weren't recognised at all, including Meter Pro, Relay Switch 1/1PM/2PM, Garage Door Opener, Plug Mini (EU), Lock Pro ($), Roller Shade and Circulator Fan. Codes with no pySwitchbot equivalent are kept. SwitchBotBLEModel is unchanged, since changing its values would be a breaking change.

Not changed (needs real hardware)

  • BLE replies are read with notify.read() rather than by waiting for a notification, as pySwitchbot does.
  • Curtain setPosition puts the speed in the OpenAPI mode field. That's correct for the default speed (ff); other speeds don't map cleanly to the documented modes 0, 1 and ff.

Checks

Build, 374 tests (+41) and lint pass. Labelled minor (5.1.0): new devices are recognised, and the rest are fixes.


Generated by Claude Code

…ds and BLE model codes

Transport
- Fall back to the OpenAPI when a BLE command fails. With connection
  intelligence on (the default), a fallback was only set when it picked a
  transport other than the preferred one, so BLE failures never reached
  the API.
- Read BLE status, lock state and Bot state by peripheral id when the MAC
  is empty (macOS); only commands handled that before.
- Enforce the circuit breaker's HALF_OPEN limit, and stop its recovery
  timer keeping the process alive.

BLE replies
- Judge a reply by its status byte (byte 0), as pySwitchbot and the BLE
  docs do. Scanning every byte read payload such as a 7% battery as
  "password required", and an error reply containing 0x01 as success.

Discovery
- Merge an OpenAPI device into its BLE device by id (the MAC without
  colons). Matching only on type strings, which differ between BLE and the
  API, dropped the API record, and with two devices of one model could
  attach the wrong device and lose the other.
- Only match by type for BLE devices with no MAC, comparing resolved
  device classes, and send API calls to the OpenAPI deviceId (new
  DeviceInfo.apiDeviceId).

OpenAPI commands (per the SwitchBotAPI device pages)
- Blind Tilt: fullyOpen, closeUp, closeDown, and setPosition as
  `direction;position`, one attempt per call.
- Air purifiers: setMode {mode, fanGear}; there is no setFanSpeed or
  setPresetMode.
- RGBIC Neon Wire Rope Light: setColor as "r:g:b".
- Color Bulb: setColorTemperature instead of the nonexistent setColorTemp.
- Vacuums: no parameters on start/dock; S10, S20, K10+ Pro Combo, K11+
  and K20+ Pro use startClean. Map "Robot Vacuum Cleaner K20 Plus Pro",
  and map S1/S1 Plus to the base vacuum class.

BLE model codes
- Align DEVICE_MODEL_MAP with pySwitchbot SUPPORTED_TYPES. Several codes
  named the wrong product (0x06 Presence Sensor, 'y' Water Leak Detector,
  0x0D Relay Switch 1PM, 0x07 Humidifier 2, ...) and many were missing
  (Meter Pro, Relay Switches, Garage Door Opener, Plug Mini (EU), ...).
  Status parsing uses the corrected Lock and Relay Switch codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s
@donavanbecker donavanbecker added the minor minor version change label Oct 24, 2026 — with Claude
@donavanbecker
donavanbecker merged commit 9c915cb into latest Oct 24, 2026
2 checks passed
@donavanbecker
donavanbecker deleted the fix/deep-dive branch October 24, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor minor version change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants