Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwitchBot Meter models passive broadcast decoding #506

Closed
brandonmpace opened this issue Jan 29, 2024 · 12 comments
Closed

SwitchBot Meter models passive broadcast decoding #506

brandonmpace opened this issue Jan 29, 2024 · 12 comments

Comments

@brandonmpace
Copy link

I want to use passive mode to listen for the broadcast messages that get sent from the SwitchBot Meter. They seem to be sent when temperature or humidity changes.

In my testing I am able to see these messages, but since they do not include the service data they are not matched and decoded.

Would it be acceptable to modify the conditions to match the manufacturer data and extract data from there?

The data I am after (temp and humidity) is included in the manufacturer data field. (these broadcast messages do not include the service data field)

In active scan mode, the data is found in both manufacturer data and service data, which get sent in that case.

Active scan has the benefit of seeing the battery level in the service data, but I only want to check that daily. Is it possible to pull the other data from the manufacturer data and just decode the battery level when it is present?

Additional context

I copied output from running https://github.com/theengs/decoder/blob/d3882a16d03a643f311190e2133670acffe5c83e/examples/python/ScanAndDecode.py

with some small modifications to allow passive mode:

# added some imports at the top
from bleak.assigned_numbers import AdvertisementDataType
from bleak.backends.bluezdbus.advertisement_monitor import OrPattern
from bleak.backends.bluezdbus.scanner import BlueZScannerArgs

# changed beginning of main() to look like this:
async def main():
    bluez_args = BlueZScannerArgs(or_patterns=[OrPattern(0, AdvertisementDataType.MANUFACTURER_SPECIFIC_DATA, b"\x69")])

    scanner = BleakScanner(bluez=bluez_args, detection_callback=detection_callback, scanning_mode="passive")
    await scanner.start()
    await asyncio.sleep(60.0)

In the below outputs, Passive is with these changes while Active is with the original script.
(MAC in outputs redacted, all but first byte replaced with FF)

Switchbot Meter (non-Plus)

# Passive:
data sent to decoder:  {"manufacturerdata": "6909ccffffffffff130305982c", "id": "CC:FF:FF:FF:FF:FF", "rssi": -57}
TheengsDecoder found device: None

# Active:
data sent to decoder:  {"servicedatauuid": "fd3d", "servicedata": "5400e405982c", "manufacturerdata": "6909ccffffffffff0b0305982c", "id": "CC:FF:FF:FF:FF:FF", "rssi": -63}
TheengsDecoder found device: {"servicedatauuid":"fd3d","servicedata":"5400e405982c","manufacturerdata":"6909ccffffffffff0b0305982c","id":"CC:FF:FF:FF:FF:FF","rssi":-63,"brand":"SwitchBot","model":"Meter (Plus)","model_id":"THX1/W230150X","type":"THB","acts":true,"tempc":24.5,"tempf":76.1,"hum":44,"batt":100}
{"properties":{"tempc":{"unit":"°C","name":"temperature"},"hum":{"unit":"%","name":"humidity"},"batt":{"unit":"%","name":"battery"}}}
brand: SwitchBot , model: Meter (Plus)

Meter Plus:

# Passive:
data sent to decoder:  {"manufacturerdata": "6909dcffffffffff25030597ac", "id": "DC:FF:FF:FF:FF:FF", "rssi": -56}
TheengsDecoder found device: None

# Active:
data sent to decoder:  {"servicedatauuid": "fd3d", "servicedata": "6900640597ac", "manufacturerdata": "6909dcffffffffff29030597ac", "id": "DC:FF:FF:FF:FF:FF", "rssi": -52}
TheengsDecoder found device: {"servicedatauuid":"fd3d","servicedata":"6900640597ac","manufacturerdata":"6909dcffffffffff29030597ac","id":"DC:FF:FF:FF:FF:FF","rssi":-52,"brand":"SwitchBot","model":"Meter (Plus)","model_id":"THX1/W230150X","type":"THB","acts":true,"tempc":23.5,"tempf":74.3,"hum":44,"batt":100}
{"properties":{"tempc":{"unit":"°C","name":"temperature"},"hum":{"unit":"%","name":"humidity"},"batt":{"unit":"%","name":"battery"}}}
brand: SwitchBot , model: Meter (Plus)

Outdoor Meter:

# Passive:
data sent to decoder:  {"manufacturerdata": "6909ddffffffffff090309972c00", "id": "DD:FF:FF:FF:FF:FF", "rssi": -55}
TheengsDecoder found device: None

# Active:
data sent to decoder:  {"servicedatauuid": "fd3d", "servicedata": "7700e4", "manufacturerdata": "6909ddffffffffff1b0309972c00", "id": "DD:FF:FF:FF:FF:FF", "rssi": -60}
TheengsDecoder found device: {"servicedatauuid":"fd3d","servicedata":"7700e4","manufacturerdata":"6909ddffffffffff1b0309972c00","id":"DD:FF:FF:FF:FF:FF","rssi":-60,"brand":"SwitchBot","model":"Outdoor Meter","model_id":"W340001X","type":"THB","acts":true,"tempc":23.9,"tempf":75.02,"hum":44,"batt":100,"mac":"DD:B6:78:C1:7C:9B"}
{"properties":{"tempc":{"unit":"°C","name":"temperature"},"hum":{"unit":"%","name":"humidity"},"batt":{"unit":"%","name":"battery"},"mac":{"unit":"string","name":"MAC address"}}}
brand: SwitchBot , model: Outdoor Meter
@brandonmpace
Copy link
Author

I see #482 for the Outdoor Meter and am interested in what other devices are picked up on accident with those changes.

Based on the comment here: 1technophile/OpenMQTTGateway#1845 (comment)
it seems to be other SwitchBot devices.

@DigiH which specific ones also send that length of manufacturerdata?

@DigiH
Copy link
Member

DigiH commented Jan 29, 2024

The data I am after (temp and humidity) is included in the manufacturer data field. (these broadcast messages do not include the service data field)

Unfortunately this is the problem with only looking at the manufacturerdata, as all SwitchBot devices have manufacturerdata which is 26 long, apart from the Outdoor Meter in your case with has one additional octet, making it 28 long. It is only the servicedata however, which includes the uniquely identifying device type octet.

So any 26 long manufacturerdata without an additional servicedata with the device type indicator could be from a SwitchBot Curtain, Motion Sensor, Contact Sensor …

So your above solution might work for your particular situation, where you only seem to have the Meter and Meter Plus, and the Outdoor Meter with its additional extra octet in its manufacturerdata, but for anyone else with some other SwitchBot devices this would not work and only produce constant mismatched decoder recognitions.

@DigiH
Copy link
Member

DigiH commented Jan 29, 2024

One thing to look at and where we got a lot of the information from for our decoders is the semi-offical SwitchBot BLE API repo, which unfortunately doesn't seem to be updated with a lot of the recent firmware and new device changes.

https://github.com/OpenWonderLabs/SwitchBotAPI-BLE

If you find any further useful information there which could improve the decoders please let us know.

@brandonmpace
Copy link
Author

brandonmpace commented Jan 29, 2024

Thank you for the info!

I can see how that makes things difficult.

Given that is the case, I guess my goal would need to be:

  • forcing decode as a particular device (e.g. based on MAC my program would request a specific device for decoding based on a pairing I made in a config file)
  • decode data that exists in manufacturerdata, and if servicedata also exists decode other items from there

That would need a new function (or new argument to decodeBLEJson, or a dedicated key inside the passed JSON) to specify a device, along with other changes.

I would understand if this is beyond the scope of this project, just let me know.

@DigiH
Copy link
Member

DigiH commented Jan 29, 2024

If you are using your own project with Theengs Decoder you might want to introduce something similar to the white-list OpenMQTTGateway uses with the Decoder library, only allowing white-listed MAC addresses to decoded and published - although you do have both the Meter, Meter Plus AND Tile ;) Is there any particular reason why you are using a custom project which incorporates Theengs Decoder, other than OpenMQTTGateway or Theengs Gateway, with the latter also being available as a HA -Add-on.

Obviously once we have the wrongly recognised Tile issue sorted out for either your project or our Theengs ones.

@brandonmpace
Copy link
Author

I am wanting BLE->MQTT, but passive scan only. (which means I need to decode these broadcasts that don't have servicedata)

If that can be achieved with either of those that would be amazing.

@DigiH
Copy link
Member

DigiH commented Jan 30, 2024

Did you get a chance to try out the false positive Tile branch?

#505 (comment)

The Outdoor Meter is already getting the temperature and humidity from the manufacturerdata, while for the Meter and Meter Plus you'd have to create your custom decoders.

@DigiH
Copy link
Member

DigiH commented Jan 31, 2024

@brandonmpace

Are you clear on how to go about creating/changing the decoders in your own fork to allow for passive scanning and the decoding of temperature and humidity? The battery status won't work for any of the Meters, as this is only ever broadcast in the servicedata.

@brandonmpace
Copy link
Author

Yes, thank you!

@DigiH
Copy link
Member

DigiH commented Jan 31, 2024

Closing, as this is only really feasible on an individual basis due to the device ambiguity of only evaluating manufacturerdata for SwitchBot devices.

@DigiH
Copy link
Member

DigiH commented Feb 20, 2024

@brandonmpace

Are you getting the same name broadcast with your SwitchBot Meters during passive scanning as this users - possibly with a newer firmware required?

#518

@brandonmpace
Copy link
Author

No new firmware available since I last checked in January.

Even after being connected to the app and named there is no name in the broadcasts.

Thank you for asking!

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

No branches or pull requests

2 participants