OpenWonderLabs / SwitchBotAPI-BLE

SwitchBot BLE open API
98 stars 9 forks source link

Advertise state changes instead of needing to ask for SCAN_RSP #15

Closed bdraco closed 1 year ago

bdraco commented 1 year ago

Current Situation

When a contact sensor or other changes state, it would be great if it advertised the change immediately instead of having to ask for a scan response. This would make the Home Assistant work with passive scanning and reflect changes right away which would allow us to solve https://github.com/home-assistant/core/issues/82795

Currently the scan response data can be stale since there is a race between when the contact sensor changes state and the scan response is received which leads to stale and incorrect states being seen.

Proposed Change

See above

Additional Context

No response

dcousens commented 1 year ago

@bdraco, I am using passive scanning only for my SwitchBot contact sensors (no connections).

The manufacturer data broadcast seems to include motion and contact flags, and two 16-bit timers, respectively, counting since their last state change (~256/second). There is a 4-bit counter too at the end of the message for built-in button presses.

The motion sensor seems to hold it's state for ~30 seconds; and I receive advertisements in quick succession in response to any state change. data[7] & 0b10000000 and data[7] & 0b00010000 seem to be motion and contact flags respectively (edit: the contact flag might actually actually be 2 bits).

Maybe @donavanbecker can help illuminate the format and describe why only the SCAN_RSP service data is used in node-switchbot.

donavanbecker commented 1 year ago

@dcousens I am not sure. I actually don't work for SwitchBot. I just maintain the nodejs repos. If someone wants to enhance node-SwitchBot, I would be happy 😀 to merge the pull request!

dcousens commented 1 year ago

Interesting! Out of curiosity, where did you source the documentation in this repository from? Maybe @Minsheng could help?

bdraco commented 1 year ago

@dcousens thats good news. How do you determine it's a contact sensor with only passive scans?

bdraco commented 1 year ago

Also do you have any docs / code to parse the manufacturer data ?

dcousens commented 1 year ago

@bdraco I determine the devices address, from it's first appearance on powering on, with the company identifier 0x0969 for the manufacturer data.

I don't have other Switchbot products for now, so I don't know if you can reasonably disambiguate them if you're thinking of automating discovery.

Also do you have any docs / code to parse the manufacturer data ?

Maybe I'll create a pull request for @donavanbecker as suggested, but I don't have any documentation other than what I have determined myself.

bdraco commented 1 year ago

but I don't have any documentation other than what I have determined myself.

Looks like we are all in the same boat on this.

Having docs for the manufacturer data would be a major improvement for the 3000+ users we have using the Home Assistant integration.

donavanbecker commented 1 year ago

Interesting! Out of curiosity, where did you source the documentation in this repository from?

This all came from the wiki that was on the python-host repo. Just moved for easier access and updating.

bdraco commented 1 year ago

https://github.com/Danielhiversen/pySwitchbot/pull/152

I can confirm the manufacturer_data gets sent passively!

I figured out 4 of the values in live testing.

        motion_detected = bool(mfr_data[7] & 0b10000000)
        contact_open = bool(mfr_data[7] & 0b00010000)
        button_count = mfr_data[12] & 0b00001111
        is_light = bool(mfr_data[7] & 0b01000000)

I still don't have a way to identify the specific device though.

bdraco commented 1 year ago

I managed to write manufacturer_data parsers for most of the devices pySwitchBot supports

It looks like the battery data isn't there though.

They are all there if anyone wants to lift them : https://github.com/Danielhiversen/pySwitchbot/tree/master/switchbot/adv_parsers

donavanbecker commented 1 year ago

@bdraco Wanna create a PR for node-SwitchBot? 😀

bdraco commented 1 year ago

@bdraco Wanna create a PR for node-SwitchBot? 😀

If I didn't have a giant backlog of other work to get done I'd be happy to do that. Sadly I'll be digging myself out of the hole for a while since adding the Bluetooth integration to Home Assistant has taken up about 10x more work than I expected 🙈

donavanbecker commented 1 year ago

If I didn't have a giant backlog of other work to get done I'd be happy to do that. Sadly I'll be digging myself out of the hole for a while since adding the Bluetooth integration to Home Assistant has taken up about 10x more work than I expected 🙈

Totally understandable, could you update this documentation? For people to better follow?

dcousens commented 1 year ago

@bdraco from my recent testing, contact_open falls low after 60 seconds; however an adjacent bit (mask & 0b00100000) comes high when that happens. That bit seems to stay high until the contact is closed.

contact_open = bool(mfr_data[7] & 0b00110000)
bdraco commented 1 year ago

It looks like now have parsers for all the manufacturer data values in pySwitchbot so I'm going to close this.

Thanks to everyone who provided input.