theengs / decoder

Efficient, portable and lightweight library for Internet of Things payload decoding.
https://decoder.theengs.io
GNU General Public License v3.0
116 stars 38 forks source link

SwitchBot Meter models passive broadcast decoding #506

Closed brandonmpace closed 6 months ago

brandonmpace commented 6 months ago

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 commented 6 months ago

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: https://github.com/1technophile/OpenMQTTGateway/issues/1845#issuecomment-1884730131 it seems to be other SwitchBot devices.

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

DigiH commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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:

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 commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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

https://github.com/theengs/decoder/issues/505#issuecomment-1914781944

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 commented 6 months ago

@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 commented 6 months ago

Yes, thank you!

DigiH commented 6 months ago

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

DigiH commented 6 months ago

@brandonmpace

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

https://github.com/theengs/decoder/issues/518

brandonmpace commented 3 months ago

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!