diff --git a/contrib/python/README.md b/contrib/python/README.md new file mode 100644 index 00000000..71068d3d --- /dev/null +++ b/contrib/python/README.md @@ -0,0 +1,16 @@ +# Quick Thermometer scan in Python + +This is intended as a demo of how to read BLE announcements in Python. It is based on [bluepy](https://github.com/IanHarvey/bluepy). + +## Usage + +``` +❯ pip3 install bluepy +[...] +❯ python3 scan-thermometer.py +{"timestamp": "2021-06-10T20:36:50+02:00", "mac": "A4:C1:38:XX:XX:XX", "temperature": 23.4, "humidity": 52, "battery_percent": 85, "battery_volt": 0.328, "count": 22} +``` + +The program terminates after reading one value, or after 10s. + +The scan is performed in passive mode. diff --git a/contrib/python/scan-thermometer.py b/contrib/python/scan-thermometer.py new file mode 100644 index 00000000..5f13b6c2 --- /dev/null +++ b/contrib/python/scan-thermometer.py @@ -0,0 +1,35 @@ +from bluepy.btle import Scanner, DefaultDelegate, BTLEInternalError +import json +from datetime import datetime + +class ScanDelegate(DefaultDelegate): + def __init__(self): + DefaultDelegate.__init__(self) + + def handleDiscovery(self, dev, isNewDev, isNewData): + for (sdid, desc, val) in dev.getScanData(): + if self.isTemperature(dev.addr, sdid, val): + print(json.dumps(self.parseData(val))) + exit() + + def isTemperature(self, addr, sdid, val): + if sdid != 22: + return False + if len(val) != 30: + return False + return True + + def parseData(self, val): + bytes = [int(val[i:i+2], 16) for i in range(0, len(val), 2)] + return { + 'timestamp': datetime.now().astimezone().replace(microsecond=0).isoformat(), + 'mac': ":".join(["{:02X}".format(bytes[i]) for i in range(2,8)]), + 'temperature': (bytes[8] * 16 + bytes[9]) / 10, + 'humidity': bytes[10], + 'battery_percent': bytes[11], + 'battery_volt': (bytes[12] * 16 + bytes[13]) / 1000, + 'count': bytes[14], + } + +scanner = Scanner().withDelegate(ScanDelegate()) +scanner.scan(10.0, passive=True)