Skip to content

fix(ble): parse sensor readings from advertisements - #357

Merged
donavanbecker merged 2 commits into
latestfrom
fix/passive-sensor-status
Oct 30, 2026
Merged

donavanbecker merged 2 commits into
latestfrom
fix/passive-sensor-status

Conversation

@donavanbecker

@donavanbecker donavanbecker commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What

Completes the fix for homebridge-switchbot#1437 (a BLE Meter shows 0 for temperature, humidity and battery).

6.0.1 (4112d4b) stopped connecting to sensors and reads them from their advertisement data instead. But on real hardware that data has no readings in it, so Meters still show 0:

  • the scanner never parsed temperature, humidity, contact, motion or leak state from advertisements;
  • it ignored manufacturer data, which is where newer Meters (and the Meter Pro CO2's CO2) put their readings;
  • it dropped non-connectable advertisements, which is how many sensors broadcast.

6.0.1's tests pass because they inject advertisement data that already contains temperature. This PR adds an end-to-end test that feeds real advertisement bytes through the scanner.

Changes (on top of 6.0.1, keeping its design)

  • src/utils/sensor-advertisement.ts (new): port of pySwitchbot's Meter (T, i, w, 4, 5), contact, motion and leak parsers (adv_parsers/meter.py, contact.py, motion.py, leak.py), covering service data plus the SwitchBot manufacturer payload. That includes Meter Pro CO2, with out-of-range values dropped as pySwitchbot does.
  • BLEScanner:
    • passes the manufacturer payload to the parser;
    • keeps non-connectable advertisements from these sensors (other non-connectable devices are still skipped).
  • SwitchBot: updates known devices from every advertisement the scanner hears, not only during discover(). Any running scan keeps sensor readings fresh, so they rarely need 6.0.1's 10 s listen.
  • Status mapping:
    • contact and motion map openState / movement / brightness from the parsed fields (they read fields the scanner never set);
    • Meter Pro CO2 reports co2 over BLE.
  • getStatusWithFallback: when the preferred transport fails and there's nothing to fall back to, it now throws that error instead of trying the same transport a second time. Previously every failed read was doubled, including the repeated connection attempts in #1437. Behaviour change: with enableFallback: false, a failed read no longer quietly tries the other transport.

Note

WoPresence also serves Presence Sensor, which has no ported parser yet. Its advertisement carries no reading, so status uses the API when one is configured.

Tests

  • test/utils/sensor-advertisement.test.ts: the parsers, checked against pySwitchbot's own fixtures and expected values.
  • test/apis/passive-sensor-status.test.ts: SwitchBot with a fake adapter and real Meter advertisement bytes. It covers:
    • a non-connectable Meter is discovered and read (24.6 °C / 53 % / 100 %) with no connection attempt;
    • a stale reading triggers a scan and picks up the new value;
    • any running scan keeps readings current;
    • with no new advertisement, the last reading is kept.
  • All of 6.0.1's sensor tests still pass.

462 tests pass. Build and lint pass.

No breaking API changes. Target: latest (6.0.2).

https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s


Generated by Claude Code

Meters, contact, motion and leak sensors report their state only in their
BLE advertisements, and pySwitchbot reads them that way. node-switchbot
connected to them over GATT instead, which many sensors refuse
("Unknown Connection Identifier (0x2)"), so their readings stayed at 0.

- Port pySwitchbot's meter, contact, motion and leak advertisement parsers,
  including manufacturer data (newer meters, Meter Pro CO2).
- Keep non-connectable advertisements from these sensors.
- Sensors read their status from the last advertisement (up to 5 minutes
  old), otherwise wait up to 10 s for the next one, running a short scan if
  none is running. They never connect; with no reading the API fallback runs.
- SwitchBot updates known devices from every advertisement it hears, not
  only during discover().
- getStatusWithFallback no longer tries the same transport twice when it
  fails and there is nothing to fall back to.

Fixes OpenWonderLabs/homebridge-switchbot#1437

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s
6.0.1 already reads sensors from advertisements instead of connecting;
keep its design (readsFromAdvertisement, bleServiceDataAt,
listenForAdvertisement) and drop this branch's duplicate of it.

What this branch still adds on top of 6.0.1: the advertisement readings
themselves. The scanner never parsed sensor readings, ignored manufacturer
data and dropped non-connectable advertisements, so the advertisement data
6.0.1 reads has no temperature or humidity and meters still show 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s
@donavanbecker donavanbecker changed the title fix(ble): read meters and other sensors from advertisements fix(ble): parse sensor readings from advertisements Oct 30, 2026
@donavanbecker
donavanbecker merged commit c82dc21 into latest Oct 30, 2026
2 checks passed
@donavanbecker
donavanbecker deleted the fix/passive-sensor-status branch October 30, 2026 22:14
donavanbecker added a commit to OpenWonderLabs/homebridge-switchbot that referenced this pull request Oct 30, 2026
## What

Updates `node-switchbot` from `^5.2.4` to `^6.0.2` ([6.0.0:
node-switchbot#355](OpenWonderLabs/node-switchbot#355),
[6.0.2:
node-switchbot#357](OpenWonderLabs/node-switchbot#357)).

## What users get

- **Encrypted BLE devices work:** the configured `encryptionKey` /
`keyId` already reach node-switchbot through `setDeviceKey` (#1432), and
6.0.0 is the version that uses them. This covers relay switches, locks,
air purifiers and bulbs.
- **Reliable command results:** BLE command replies are read from
notifications, as in pySwitchbot.
- **No more disconnect warnings:** `Unexpected disconnect` is no longer
logged after every BLE command. A device that drops the link is
reconnected on the next command.

- **BLE Meters and sensors read correctly:** Meters, contact, motion and
leak sensors are read from their advertisements instead of by
connecting, which many refuse. Fixes #1437, where Meters showed 0.

## Compatibility

- 6.0.0's breaking change is the `SwitchBotBLEModel` values. The plugin
doesn't switch on them, so no code changes are needed.
- Build passes, 219 tests pass and lint passes against 6.0.2.
- The lockfile was regenerated with npm 11. Only the `node-switchbot`
entries change.

## Target

No beta branch existed, so I created `beta-5.2.10` from `latest` (next
patch after the published 5.2.9; there are no labels).

No config migration needed.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01TYWa2RXoWsaUTWh76oNv8s)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
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