Skip to content

feat: port pySwitchbot 3.2.0-3.8.1 - #362

Merged
donavanbecker merged 1 commit into
latestfrom
feat/pyswitchbot-3.8.1
Nov 13, 2026
Merged

donavanbecker merged 1 commit into
latestfrom
feat/pyswitchbot-3.8.1

Conversation

@donavanbecker

Copy link
Copy Markdown
Contributor

What

This ports pySwitchbot 3.2.0 through 3.8.1:
3.2.0,
3.2.1,
3.3.0,
3.3.1,
3.3.2,
3.4.0,
3.5.0,
3.6.0,
3.7.0,
3.8.0,
3.8.1.

It also fixes three lock and product-ID bugs found while porting. Each new lock depends on them.

Ported from pySwitchbot

pySwitchbot change node-switchbot
UWB Lock (#599), Lock Nano (#600), Lock Ultra Max New lock models. Each gets pySwitchbot's commands, advertisement parsing and product ID. Classes: WoSmartLockUltra (Lock Ultra, Ultra Max, UWB Lock, grouped as in pySwitchbot) and WoSmartLockNano.
Lock Ultra Quick Key (#515) WoSmartLockUltra.getQuickKey() / setQuickKey(), plus halfLock().
Bot inverse direction (#543) WoHand.setInverseDirection(), which keeps the mode and strength, and getModeSettings().
Hub 4 (#605, #606) WoHub4, with the Hub 4 OpenAPI device type.
Plug Mini (IT) (#602), Outdoor Plug (EU) (#604) OpenAPI device types, mapped like the Plug Mini (EU).

Fixes found while porting

  1. Product IDs. Newer SwitchBot products have no model byte. pySwitchbot identifies them by the 4-byte product ID at the end of the service data (_find_model_from_service_data_suffix). node-switchbot only knew model bytes, so it never recognised any of these products over BLE. pySwitchbot lists 29 of them, including Hub 3, the Lock Ultra and Lock Vision family, Floor Lamp, the RGBICWW lights and Climate Panel.
    • The lookup is ported as findProductId / PRODUCT_ID_MODEL_MAP.
    • Only the lock family is listed for now. Recognising a product over BLE makes its status BLE-first, so a product whose BLE support is unfinished would swap good cloud data for bad. The rest are listed below as follow-ups.
  2. Lock commands never matched the lock protocol.
    • Lock Pro "lock" sent 57 0f 4f 01 00. 4f is the lock info command; pySwitchbot locks with 57 0f 4e 01 01 00 00 00.
    • Lock sent 57 0f 4e 01 00 instead of 57 0f 4e 01 01 10 00.
    • Locks now use pySwitchbot's per-model tables (LOCK_COMMANDS), chosen by the lock model from the device type. That covers lock, unlock, unlock without unlatch, info, notifications, and half lock on the Lock Ultra.
    • The old WoSmartLockCommands / WoSmartLockProCommands exports are kept as @deprecated.
  3. Lock state was read from the wrong place. It came from service-data byte 1, or from a raw GATT read of an encrypted lock. Locks now read it from the manufacturer data in advertisements, using pySwitchbot's layout for each lock family (src/utils/lock-advertisement.ts).

Not applicable here

  • Circulator Fan Pro firmware query (#611) and the RGBICWW ceiling light aggregate power (#609): node-switchbot has no such classes.
  • Lock Ultra basic-info battery/firmware (#601): node-switchbot doesn't read lock basic info.
  • Temporary-device disconnect after key verification (#613): node-switchbot has no such flow.

Follow-ups, not in this PR

These product IDs are known from pySwitchbot, but node-switchbot's BLE status or commands for them aren't ported yet, so they stay cloud-only:

  • Hub 3 and Hub 4: advertisement parsing.
  • Plug Mini (EU/IT) and Outdoor Plug (EU): an encrypted relay class and power metering.
  • Floor Lamp, Strip Light 3, RGBICWW lights, Permanent Outdoor Lights, neon rope lights.
  • Climate Panel, Smart Radiator Thermostat, Presence Sensor, Art Frame, Keypad Vision / Vision Pro.
  • K11+ and S20 vacuums, Standing Fan.

Tests

  • test/utils/lock-advertisement.test.ts: every lock family, using pySwitchbot's own advertisement fixtures and expected values.
  • test/devices/pyswitchbot-3.8.test.ts:
    • each lock model's command bytes against pySwitchbot's tables, and the bytes each class actually sends;
    • product-ID recognition;
    • lock state from manufacturer data;
    • Quick Key read and write, using pySwitchbot's test_lock.py vectors;
    • half lock;
    • the new device types;
    • Bot inverse direction, using pySwitchbot's test_bot.py vectors (57034b10 / 57034b11).

510 tests pass. Build and lint pass.

Migration notes (homebridge-switchbot)

  • No breaking API changes.
  • Lock Ultra / Smart Lock Ultra now create WoSmartLockUltra, a subclass of WoSmartLockPro, so instanceof WoSmartLockPro still holds.
  • New device types to map in the plugin: Lock Ultra Max, UWB Lock, Lock Nano, Hub 4, Plug Mini (IT), Outdoor Plug (EU).
  • Locks need their key (setKey({ keyId, encryptionKey })) for BLE commands, as before.

Labelled minor (6.1.0).


Generated by Claude Code

New in pySwitchbot 3.2.0-3.8.1:
- UWB Lock, Lock Nano and Lock Ultra Max: lock models with pySwitchbot's
  commands, advertisement parsing and product IDs.
- Lock Ultra Quick Key: getQuickKey / setQuickKey (WoSmartLockUltra), and
  half lock.
- Bot inverse direction: setInverseDirection keeps the mode and strength;
  getModeSettings reads them.
- Hub 4, Plug Mini (IT) and Outdoor Plug (EU) OpenAPI device types.

Fixes found while porting:
- Product IDs: newer products have no model byte and are identified by
  the 4-byte product ID at the end of the service data. node-switchbot
  only knew model bytes, so no such product was recognised over BLE. The
  lookup is ported; the lock family is listed.
- Lock commands never matched the lock protocol (the Lock Pro "lock" sent
  the lock info command, 57 0f 4f). Locks now use pySwitchbot's
  per-model tables, picked from the device type.
- Lock state was read from service data byte 1 and by a raw GATT read of
  an encrypted lock. It now comes from the manufacturer data in
  advertisements, with pySwitchbot's layout for each lock family.

Not applicable: the Circulator Fan Pro firmware query and the RGBICWW
ceiling light power state (no such classes here), the Lock Ultra
basic-info battery fix (node-switchbot does not read lock basic info),
and the encryption-key verification disconnect (no such flow here).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s
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