#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # sbm2mqtt.py https://github.com/ronschaeffer/sbm2mqtt # # Based in part on: # https://github.com/OpenWonderLabs/python-host # https://github.com/bbostock/Switchbot_Py_Meter # https://qiita.com/warpzone/items/11ec9bef21f5b965bce3. # # Substantial contribution from @shish to simplify scanning and building of JSON from bluepy.btle import Scanner, DefaultDelegate, ScanEntry import datetime import paho.mqtt.client as mqtt import json # Import configuration variables from sbm2mqtt_config.py file - Must be in the same folder as this script from sbm2mqtt_config import ( mqtt_host, mqtt_port, mqtt_timeout, mqtt_client, mqtt_user, mqtt_pass, mqtt_topic, ) # SwitchBot UUID - See https://github.com/OpenWonderLabs/python-host/wiki/Meter-BLE-open-API service_uuid = "cba20d00-224d-11e6-9fb8-0002a5d5c51b" class ScanDelegate(DefaultDelegate): # Scan for BLE device advertisements, filter out ones which are not SwitchBot Meters & convert the service data to binary def handleDiscovery(self, dev, isNewDev, isNewData): services = dev.getValue(ScanEntry.COMPLETE_128B_SERVICES) service_data = dev.getValue(ScanEntry.SERVICE_DATA_16B) # Check for model "T" (54) in 16b service data if ( services and services[0] == service_uuid and service_data and len(service_data) == 8 and service_data[2] == 0x54 ): mac = dev.addr binvalue = service_data # Get temperature and related characteristics temperature = (binvalue[6] & 0b01111111) + ( (binvalue[5] & 0b00001111) / 10 ) # Absolute value of temp if not (binvalue[6] & 0b10000000): # Is temp negative? temperature = -temperature if not (binvalue[7] & 0b10000000): # C or F? temp_scale = "C" else: temp_scale = "F" temperature = round( temperature * 1.8 + 32, 1 ) # Convert to F # Get other info humidity = binvalue[7] & 0b01111111 battery = binvalue[4] & 0b01111111 # Get current time time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Print info to terminal print("\n" + mac + " @ " + str(time)) print(" Temp: " + str(temperature) + "\u00B0" + temp_scale) print(" Humidity: " + str(humidity) + "%") print(" Battery: " + str(battery) + "%") # MQTT publish as JSON msg_data = json.dumps({ "time": time, "temperature": temperature, "humidity": humidity, "battery": battery, "temperature_scale": temp_scale, "signal_strength": dev.rssi, }) print( "\n Publishing MQTT payload to " + mqtt_topic + "/" + mac + " ...\n\n " + msg_data ) mqttc = mqtt.Client(mqtt_client) mqttc.username_pw_set(mqtt_user, mqtt_pass) mqttc.connect(mqtt_host, mqtt_port) mqttc.publish(mqtt_topic + "/" + mac, msg_data, 1) def main(): print("\nScanning for SwitchBot Meters...") scan = scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(10.0) print("\nFinished.\n") if __name__ == "__main__": main()