#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # sbm2web.py by Thomas Rudolph # Proof of concept to read values from Switchbot Meters TH S1 and write # them to an HTML file. This program can be run automatically in intervals # by using, e.g., cron # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Based in part on: # https://github.com/OpenWonderLabs/python-host # https://github.com/bbostock/Switchbot_Py_Meter # https://qiita.com/warpzone/items/11ec9bef21f5b965bce3. # https://github.com/ronschaeffer/sbm2mqtt by Ron Schaeffer # # from bluepy.btle import Scanner, DefaultDelegate, ScanEntry import datetime # SwitchBot UUID - See https://github.com/OpenWonderLabs/python-host/wiki/Meter-BLE-open-API service_uuid = "cba20d00-224d-11e6-9fb8-0002a5d5c51b" # Change the name of the HTML file according to your needs html_filename = "index.htm" class ScanDelegate(DefaultDelegate): # Scan for BLE device advertisements, filter out ones which are not SwitchBot Meters & convert the service data to binary time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Write HTML header and CSS to file f = open(html_filename, 'w') f.write("\n\n\nBluetooth-Thermometer\n") f.write("🌡️\">") f.write("Letztes Update: ") f.write(time) f.write("

\n") f.close() 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") # Calculate colours for temperature display in HTML temprot = int((temperature+10)*6) tempblau = int(255-(temperature+10)*6) f = open(html_filename, 'a') f.write("
") # You can define an if/elif case for every device MAC you own to give it a name instead a MAC address if dev.addr == "eb:f8:b8:03:0c:de": f.write("Studio") elif dev.addr == "dd:02:d9:f8:c3:b2": f.write("Orangerie") else: f.write(str(dev.addr)) # Write sensor measurements to HTML f.write("
\n") f.write(str(temperature) + "\u00B0" + temp_scale) f.write("💧️ " + str(humidity) + "%
") f.write("🔋️ " + str(battery) + "%
") f.write("📡️ " + str(dev.rssi) + "dBm
\n") # Print info to terminal print("\n" + mac + " @ " + str(time)) print(" Temperature:\t " + str(temperature) + "\u00B0" + temp_scale) print(" Humidity:\t " + str(humidity) + "%") print(" Battery:\t " + str(battery) + "%") print(" Signal:\t " + str(dev.rssi) + "dBm") print(" Unit:\t\t °" + str(temp_scale)) f.close() def main(): print("\nScanning for SwitchBot Meters...") scan = scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(10.0) print("\nFinished.\n") if __name__ == "__main__": main()