Philips Sonicare Integration for Bluetooth Toothbrushes

I think there might be an issue of discovering and therefore adding/integrating toothbrushes if not connected directly to the native bluetooth interface of Home Assistant.

In other words: if you use a (ESPhome based) Bluetooth Proxy, you won’t be able to integrate the toothbrush.

Details: Not working with Bluetooth Proxies (ESP32 based) · Issue #14 · GrumpyMeow/sonicare-ble-hacs · GitHub

Is it worth to create an issue at Issues · esphome/issues · GitHub maybe? Up to now it’s not quite sure if the integration can’t handle Bluetooth Proxy or vice versa.

Please share (at Not working with Bluetooth Proxies (ESP32 based) · Issue #14 · GrumpyMeow/sonicare-ble-hacs · GitHub) if you use BT proxy or similar methods.

3 Likes

I assume it is more about the integration. Even directly next to my Pi (running HA) the sonicare is detected (mac address shown) but connection does not work.

1 Like

Maybe it depends on the toothbrush. My daughters’ toothbrush (Sonycare4Kids) does work well with this integration as long as it as no proxy is used. Unfortunately, my daughter is not willing to brush her teeth in the hallway just for having a direct connection to Home Assistant…

2 Likes

I picked up a set of the Philips Sonicare DiamondClean (HX9912) toothbrushes at Costco, in hopes that I could get them to work with HA. They were not detected by my production instance of HA, so I installed GrumpyMeow’s HACS add-on on my non-prod. After it didn’t detect them either, I realized that I had bluetooth disabled. After enabling and turning on the new brush, it showed up as a detected device. I tried adding, but it failed several times. The last attempt, I moved the brush closer to my Pi and it added. It’s now tracking 10 entities from the brush. I’m a little concerned with how close the brush may need to be to the Pi. Also, not sure yet if it will work with my prod HA since I do have 3 ESPHome devices. From reading above, it seems that ESPHome may not work. Happy to update as I find more information, but thought I’d pass along some encouraging progress since others may be wondering if Sonicare will work in HA.

2 Likes

Were you ever able to do more testing? I’m thinking of buying these toothbrushes. Thanks in advance!

I wasn’t able to get grumpymeow’s Sonicare BLE HACS integration installed (doesn’t show up on the list in HACS and adding a custom repository tells me that it already exists in the directory).

So instead, I set up an ESP32 BLE Client and connected to the toothbrushes directly. I found the range to be excellent. While testing, the toothbrushes and ESP32 were on different floors.

1 Like

Very cool!

Wondering what toothbrushes this works with. Any chance these bluetooth enabled SoniCare kids would work? Amazon.com: Philips Sonicare for Kids 3+ Bluetooth Connected Rechargeable Electric Power Toothbrush, Interactive for Better Brushing, Pink, HX6351/41

1 Like

Those are the same toothbrushes that I connect to.

I would think this method of using an ESPHome BLE Client would work for any Sonicare toothbrush. Some of the toothbrushes have more functionality than others, so service_uuid and characteristic_uuid may change but they can be determined using a bluetooth scanner like nRF Connect (on Android at least).

We just got these toothbrushes for Christmas so I hoping to get this connected like you’ve done. Forgive me if this is obvious, but how did you get the Mac address of the toothbrush?

If you wanna get the MAC using an ESP32, just add this to your device and flash it (wirelessly if fine):

esp32_ble_tracker:
  on_ble_advertise:
    - then:
        - lambda: |-
            // Stores MAC addresses of discovered Sonicare devices
            static std::vector<std::string> known_sonicare_addrs;
            
            // Check if device name starts with "Philips Sonicare"
            if (x.get_name().rfind("Philips Sonicare", 0) == 0) {
              const auto addr = x.address_str();
              
              // Skip if device already discovered
              if (std::find(known_sonicare_addrs.begin(), 
                          known_sonicare_addrs.end(),
                          addr) != known_sonicare_addrs.end()) {
                return;
              }
              
              // Add new device to known addresses
              known_sonicare_addrs.push_back(addr);
              
              // Log discovery of new device
              ESP_LOGW("ble_adv", "New sonicare device");
              ESP_LOGW("ble_adv", "  MAC: %s", addr.c_str());
              ESP_LOGW("ble_adv", "  name: %s", x.get_name().c_str());
              
              // Build comma-separated list of all known MACs
              std::string mac_list;
              for (size_t i = 0; i < known_sonicare_addrs.size(); i++) {
                mac_list += "MAC" + std::to_string(i+1) + ": " + 
                           known_sonicare_addrs[i];
                
                if (i < known_sonicare_addrs.size() - 1) {
                  mac_list += ", ";
                }
              }
              
              // Publish updated MAC address list
              id(sonicare_detected_addrs).publish_state(mac_list.c_str());
            }

text_sensor:
  - id: sonicare_detected_addrs
    name: Sonicare detected MAC
    platform: template
    # entity_category: config
    update_interval: never
    lambda: |-
      return {};

After booting up your device, keep your eyes on the logs and take your toothbrush from it’s base. In a few seconds it will report itself and your ESP32 will capture that into the logs.

Once you take notes of your MAC addresses, you can remove the code above entirely.

1 Like

I’ve forked the GrumpyMeow’s addon and applied some fixes, but it still has some issues. Most notably, it seems to read battery state probably only shortly after the first connection, and then ignore it until HA restart. But it seems to work much better than the original addon: GitHub - v6ak/sonicare-ble-hacs: Sonicare BLE HACS integration

My main reason for the integration was smart charging that keeps around 50 % of charge. I’ve kind of succeeded – when I have no information about battery state, I blindly charge for some time (15 minutes, I think), otherwise, I decide based on the battery charge level. But still, the ESP32-based integration seems to be worth trying.

1 Like

Thanks @EdwardTFN - quite to new to ESPs and ESPhome. (This is my second project!). Do I add that to the configuration YAML that @iamjosh provided or do I flash the ESP with that code separately?

1 Like

You can add that to an existing project like that one. :wink:

2 Likes

Having trouble getting this going. @EdwardTFN I’ve added your code to the config file and flashed the device. It validates in ESPHome and installs great. It’s added to Home Assistant and I see the new MAC address sense.

But it simply does not see Toothbrushes. I’ve even tried to just do a simple vanilla bluetooth proxy device with the added code. again. seems to work but never discovers the tooth brushes.

For what it’s worth, I’m using ESP32 WROOM-32 development boards from Aliexpress. Do I need to do anything extra to enable bluetooth on the esp32?

Thank you.

1 Like

The code I’ve shared will only help on discovering your toothbrush Mac address, not connecting to the toothbrush, which requires the code suggested by @iamjosh here.

If you are not getting any mac address with my code, then try changing this line:

By this:

if (true) {

This will remove the filter for Philips and will show any device broadcasting in BLE. You may get a big list, but your toothbrush should be there.

1 Like

Got the MAC addresses with @EdwardTFN’s but changing the one line in the code. Thanks!

Now I’m onto installing @iamjosh’s config on the esp.

Unfortunately, I’m getting stuck with the following lines:

./esp32-bluetooth-proxy-e9289c.yaml: In lambda function:
./esp32-bluetooth-proxy-e9289c.yaml:145:11: error: 'LittleEse' was not declared in this scope
./esp32-bluetooth-proxy-e9289c.yaml:148:9: error: 'LittleEse' was not declared in this scope

Not sure if this is a typo? Or hyper-relevant to your setup @iamjosh?

Change from LittleEse to else and it should work.

Ah, that is a typo from when I was obfuscating my kids’ names. It should be else like EdwardTFN mentioned.

Sorry about that.

Edit: lots of that typo spread throughout. Updating the example yaml on github.

3 Likes

Counted 12 instances of it. :wink: