[<< | Prev | Index | Next | >>]

Monday, January 06, 2020

Python API for wireless bluetooth thermometer (CVS/SmartTemp/Various..)



[Technical entry: Wireless Bluetooth Thermometer, SmartTemp, Python]

I wanted a wireless thermometer to track my newborn as she sleeps (currently just to see if she's at a comfortable temperature since she can't easily tell us if she's too hot or too cold) and to my surprise they exist and can be found fairly cheaply (currently about $14 on Amazon under the CVS brand, but it looks like they can be had even cheaper on Ebay under various other names). Everybody seems to hate the (SmartTemp) app that goes with it, but I just happened to write a Bluetooth library for Python so I thought I'd take the gamble that I could reverse engineer the protocol. Turns out that took about ten minutes, and it works great. Here's the code (uses the Btle lib from my prior post; slightly updated--ping me if interested; for now I'm assuming nobody cares):

#!/usr/bin/python3

from Btle import BtleDevice
import struct, bluepy
from time import sleep

class SmartTemp(BtleDevice):

    def __init__(self, mac_addy):
        BtleDevice.__init__(self, mac_addy)

    def run(self):

        try:
            while True:

                while not self.connected():
                    print("Connecting...")
                    try:
                        self.connect()
                    except bluepy.btle.BTLEDisconnectError as e:
                        print("Unable to connect.  Trying again in 1 minute (%s)"%(e,))
                        sleep(60)
                    else:
                        print("Connected.")

                try:
                    handledata = self.wait_for_notification()
                except bluepy.btle.BTLEDisconnectError:
                    print("Device disconnected.  Shutting down old connection...")
                    self.disconnect()
                else:
                    if handledata is None:
                        print("Wait_for_notification returned None even though no timeout given.")
                        break
                    handle, data = handledata
                    if handle == 0x18 and len(data) == 8:
                        temp = struct.unpack('<H', data[-4:-2])[0]
                        print("Temperature: %.2fC / %.2fF"%(temp/100, temp/100*9/5+32))

        finally:
            self.disconnect()


st = SmartTemp("AA:BB:CC:DD:EE:FF") # <- MAC addy of your thermometer goes here...
st.run()

(Technically I didn't even need to create a new class there but I'm assuming I'll wrap a cleaner API around that and use it elsewhere...)

The device itself seems to work fine. It sends a temp update every six seconds or so if the temp is changing, or less often when it's not. Even the app that comes with it seems ok, except that it asks for various permissions it shouldn't need, which is one of the many reasons I just write my own...



[<< | Prev | Index | Next | >>]


Simon Funk / simonfunk@gmail.com