Support for Tempo Disc bluetooth temperature, humidity and dew point monitor and logger

Is there support for this thing? https://bluemaestro.com/products/product-details/bluetooth-temperature-sensor-beacon. Can be purchased at a number of places, newegg, amazon etc (it’s 28.99 GBP on Amazon).

It’s made by a UK company, and looks pretty good. It also claims to have an API for integration (see Specifications tab on the webpage) but I haven’t found their API docs or SDK on their website. It appears they should be here https://support.bluemaestro.com/support/solutions/articles/47000258573-android-sdk but there are no actual docs or any SDK links.

Looks like it could be a nice addition to HA (theoretically). Anyone?

I’ve got a few Pycom LoPy4s and have code running on two of them that receives the BLE adverts from a bunch of Tempo Discs and publishes to MQTT and on to HA.

So, If anyone wants to see a code snippet (MicroPython) for parsing their advert payloads I can provide it.

1 Like

That would be very useful for me!! I just bought one of these guys off Amazon to test.

Here’s the class that I currently use on my LoPy4 BLE/MQTT gateway. I haven’t yet got around to changing the MQTT to be HA autodiscovery compatible, but I have a bunch of hand configured MQTT sensors working.

import time
import utime
import ustruct
import ubinascii
from network import Bluetooth

class Bleeater:
    def __init__(self, node, interval = 11):
        self.node = node
        self.bluetooth = Bluetooth()
        self.bluetooth.init()
        self.interval = interval
        self.running = True

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.running = False

    def work(self):
        print('Starting BLE scan')
        self.bluetooth.start_scan(11)
        while self.bluetooth.isscanning() and self.node.is_running():
            utime.sleep_ms(100)
        if self.node.is_running() and self.running:
            now = utime.localtime()
            nowstr = '{0:04d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}'.format(now[0],now[1],now[2],now[3],now[4],now[5])
            adv_list = self.bluetooth.get_advertisements()
            for adv in adv_list:
                if adv != None:
                    #print("Time: {0} adv.rssi: {1}".format(time.time(), adv))
                    # try to get the complete name
                    name = self.bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)
                    macstr = str(ubinascii.hexlify(adv.mac), "utf-8")
                    # try to get the manufacturer data
                    mfg_data = self.bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_MANUFACTURER_DATA)
                    if name != None:
                        publishables = {}
                        publishables.update({'advert/summary/'+macstr:name+' '+str(adv.rssi)+'dB'+' at '+nowstr})
                        #publishables.update({'advert/source/'+macstr+'/name':name})
                        #publishables.update({'advert/source/'+macstr+'/rssi':str(adv.rssi)})
                        #publishables.update({'advert/source/'+macstr+'/time':nowstr})
                        if mfg_data != None:
                            #publishables.update({'advert/source/'+macstr+'/manufdata':str(ubinascii.hexlify(mfg_data), "utf-8")})
                            # support for BlueMaestro Tempo Disc devices
                            fmt='!HBBIhHhH'
                            fmtsize=ustruct.calcsize(fmt)
                            if fmtsize == len(mfg_data):
                                values = ustruct.unpack(fmt, mfg_data)
                                if values[0] == 0x3301: # the BlueMaestro magic number
                                    topic = 'sensor/'+name
                                    # all Tempo Discs send battery level and temperature
                                    publishables.update({topic+'/battery'      :'{0:3.1f}'.format(float(values[2]))})
                                    publishables.update({topic+'/temp'         :'{0:3.1f}'.format(float(values[4])/10.0)})
                                    if values[1] == 0x17 or values[1] == 0x1b: # THD or THPD (does not send D!)
                                        publishables.update({topic+'/humidity' :'{0:3.1f}'.format(float(values[5])/10.0)})
                                    if values[1] == 0x17: # THD
                                        publishables.update({topic+'/dewpoint' :'{0:3.1f}'.format(float(values[6])/10.0)})
                                    elif values[1] == 0x1b: # THPD (sends P instead of D, no D is sent)
                                        publishables.update({topic+'/pressure' :'{0:3.1f}'.format(float(values[6])/10.0)})
                                else:
                                    print('BLE: Ignored mismatched ID.')
                            else:
                                print('BLE: SIZE FAIL, fmtsize: '+str(fmtsize)+' len(mfg_data): '+str(len(mfg_data)))
                        print(name+' '+str(publishables))
                        for key,value in publishables.items():
                            if key != None and value != None:
                                self.node.client_try_publish(self.node.service+'/ble'+'/'+key, value, False, 0)
                                self.node.led_flash(0x000010)
                                utime.sleep_ms(10)
                utime.sleep_ms(10)
            return len(adv_list) > 0
        else:
            return False

Daren,

Can you share your code ? I’m very newbie in programmation, so your code will be very nice to play with

Bluemaestro support has been added to BLEmonitor

1 Like