Oral-B BLUETOOTH CONNECTED TOOTHBRUSH

Has anyone here thought about an integration with Oral-B Bluetoothe (BLE) Toothbrushes? :slight_smile:

this to see the device status battery %

but also that you are brushing your teeth in the morning before leaving or in the evening before going to bed and can use it for a trigger.

information about the rest API https://developer.oralb.com/

i hope there will be more people interested and there is somebody who can build an integration

Hi,

I did a simply implementation as a sensor detecting if the mac of the toothbrush is on range. If it is then I know that it’s working.

If anyone did the implementation of the api i’m also interested!

Thanks,
Danny

Anything ever happen with this? Recently got one and have been thinking of things I could do if it was up and running yet.

Thanks.

Battery level indicator would be neat for two toothbrush household with one charger!

Found some reverse engineering progress here (not by me) to maybe build upon:

Here is a standalone implementation able to display received packets from your toothbrush. By piping into an external program it is easy to make the information available to Home Assistant over MQTT (see example).

Only tested on Linux. Battery level not implemented (yet if available at all).

i hacked together a worker for bt-mqtt-gateway that collects the info that this script collects from my oral-b-toothbrushes. i hope to file a pull request there soon. this is the bt-mqtt-gateway-worker that works fine for me so far. needs a bit of polishing …

(@molobrakos implementation got me into dependency hell which i couldn’t solve on raspbian.)

import time
from interruptingcow import timeout
from bluepy.btle import Scanner, DefaultDelegate
from mqtt import MqttMessage
from workers.base import BaseWorker
from logger import _LOGGER

import sys
from datetime import datetime
import codecs

REQUIREMENTS = ['bluepy']

class ScanDelegate(DefaultDelegate):
  def __init__(self):
    DefaultDelegate.__init__(self)

  def handleDiscovery(self, dev, isNewDev, isNewData):
    if isNewDev:
      _LOGGER.debug("Discovered new device: %s" % dev.addr)

class ToothbrushWorker(BaseWorker):
  def searchmac(self, devices, mac):
    for dev in devices:
      if dev.addr == mac.lower():
         return dev

    return None

  def status_update(self):
    scanner = Scanner().withDelegate(ScanDelegate())
    devices = scanner.scan(5.0)
    ret = []

    for name, mac in self.devices.items():
      device = self.searchmac(devices, mac)
      if device is None:
        ret.append(MqttMessage(topic=self.format_topic(name+'/presence'), payload="0"))
      else:
        ret.append(MqttMessage(topic=self.format_topic(name+'/presence/rssi'), payload=device.rssi))
        ret.append(MqttMessage(topic=self.format_topic(name+'/presence'), payload="1"))
        _LOGGER.debug("text: %s" % device.getValueText(255) )
        bytes_ = bytearray(bytes.fromhex(device.getValueText(255)))
        ret.append(MqttMessage(topic=self.format_topic(name+'/running'), payload=bytes_[5] ))
        ret.append(MqttMessage(topic=self.format_topic(name+'/pressure'), payload=bytes_[6] ))
        ret.append(MqttMessage(topic=self.format_topic(name+'/time'), payload=bytes_[7]*60 + bytes_[8] ))
        ret.append(MqttMessage(topic=self.format_topic(name+'/mode'), payload=bytes_[9] ))
        ret.append(MqttMessage(topic=self.format_topic(name+'/quadrant'), payload=bytes_[10] ))

    return ret

configuration:

toothbrush:
  args:
    devices:
      ix: 5c:f8:xx:xx:xx:xx
      ia: 2C:6B:xx:xx:xx:xx
    topic_prefix: toothbrush
  update_interval: 10

Nice!

(@molobrakos implementation got me into dependency hell which i couldn’t solve on raspbian.)

I’m running this on raspbian myself.

pip3 complained a lot, when i tried installing:

Requested 'dbus-1 >= 1.8' but version of dbus is 1.6.8
Requested 'cairo >= 1.13.1' but version of cairo is 1.12.16

the versions that i could install via apt-get were not new enough. i could compile a newer version of dbus by myself, but failed getting or compiling cairo >= 1.13.1

RE: Battery Level

does
gatttool -b {$mac} --char-read --uuid=0x2A19 -t public
or
gatttool -b {$mac} --char-read --uuid=0x2A19 -t random
return a HEX value (replace {$mac} with the MAC Address? Is so that’s reading the bluetooth battery level (I use this for my BLE Bike light, Smart Watch, and other bike sensors)

I have a bit of a convoluted setup of Home Assistant doing the following:-

  • The Bluetooth LE Device Tracker detects the device comes into range
  • This runs a REST command when the BLE device comes into range calling a webpage on my PiHole server
  • This writes a flag file to disk
  • Every 60 seconds a cron task looks for these flag files and if one exists runs the gattool command (public version and if that fails random - it’s a mixed bag as to which works)
  • The output of this command is written to a JSON file
  • This also calls http://hassip:8123/api/states/sensor.{$sensor} to update Home Assistant.
  • Another cron runs every 10 minutes resubmitting the data from the JSON Files to Home Assistant (so you don’t have to wait for the device to be used again when HASS restarts - they appear within 10 minutes)

It’s convoluted as I needed to use a Bluetooth Adapter which isn’t already in use for presence detection so it uses the Bluetooth Adapter on my UniFi Controlled / Pi Hole Machine. All the devices I have keep the BLE Active for 10 minutes so this works fine for me.

Coupled with a few other ways of gathering battery level gives a centralised display of battery levels https://i.imgur.com/GoEdK9n.png

$ gatttool -b 5c:f8:21:xx:xx:xx --char-read --uuid=0x2A19 -t public
Read characteristics by UUID failed: No attribute found within the given range

it made the LED-ring on my toothbrush blink however …
-t random times out:

$ gatttool -b 5c:f8:21:xx:xx:xx --char-read --uuid=0x2A19 -t random
connect error: Connection refused (111)

So the first one shows it connected successfully, however it doesn’t expose the (standard) BLE Battery Service. :frowning:

hi how can i find the ix: 5c:f8:xx:xx:xx:xx and ia: 2C:6B:xx:xx:xx:xx of the my toothbrush?