Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not working with Bluetooth Proxies (ESP32 based) #14

Open
bcutter opened this issue Sep 19, 2023 · 42 comments
Open

Not working with Bluetooth Proxies (ESP32 based) #14

bcutter opened this issue Sep 19, 2023 · 42 comments

Comments

@bcutter
Copy link

bcutter commented Sep 19, 2023

While I was lucky to initialy set up this integration without any issues (#2 (comment)), I discovered by manually reloading the integration that:

  • it will find the toothbrush just fine if it is pretty close to the Home Assistant server - a Raspberry Pi 4 which uses native Bluetooth
  • it will NEVER EVER find the toothbrush if next to a Bluetooth Proxy (ESP powered, https://esphome.github.io/bluetooth-proxies/) - at the same time it can be discovered using the "LightBlue" app on an iPhone also next to the BT Proxy ESP

So where's the issue? Is it the BT proxy or this Sonicare BLE integration?

I bet this is one of the reasons for the most open "Can't connect to XYZ" issues in this integration, so really worth looking into this @GrumpyMeow! We should probably start asking for the specific bluetooth environment people use. I already found few users stating they are also using Bluetooth Proxy (e. g. here: #2 (comment)).

@badewanne1234
Copy link

Thanks for sharing this. As stated, I can see the advertising messages of the Toothbrush in the BT Proxy Log, so I think it might be an issue of how the Sonicare integration reads/interprets these advertisement messages OR is the raspi BT passing BT messages differently than the ESP32 based BT proxies?

@bcutter
Copy link
Author

bcutter commented Sep 19, 2023

it might be an issue of how the Sonicare integration reads/interprets these advertisement messages OR is the raspi BT passing BT messages differently than the ESP32 based BT proxies?

That's exactly the question I hope bluetooth experts like @GrumpyMeow can verify.

By the way: by only activating my toothbrush next to the BT proxy I could not find any activity in the logs (ESPHome). If i trigger other bluetooth devices (like SwitchBot buttons) next to the BT proxy, I see quite some activity.

@badewanne1234
Copy link

I think I played around with the advertising window / intervalls and could see the activity immediately when lifting the TB out of the glass...

@edwardtfn
Copy link
Contributor

edwardtfn commented Sep 20, 2023

So, I've teste getting quite close to the server (like 2m) and the toothbrush was finally discovered. 😃

Now I will vote to add support for Bluetooth proxy. 😉

@bcutter
Copy link
Author

bcutter commented Oct 25, 2023

@GrumpyMeow

@PV-Web
Copy link

PV-Web commented Nov 13, 2023

Same problem. Bluetooth proxy via the M5 atom lite via ESP home. @GrumpyMeow
Hopefully you got time to check were this could go wrong.

@helmerzNL
Copy link

My toothbrush does connect if i'm close to my HA instance, but not from a Bluetooth Proxy. So, it would be great if support for Bluetooth proxies can be added.

@bcutter
Copy link
Author

bcutter commented Nov 20, 2023

@GrumpyMeow are you reading/still maintaining this project?

@rigwig
Copy link

rigwig commented Jan 4, 2024

Same issue here, am able to connect via HA intgrated bt, but no luck via an esp32 based proxy.

@bcutter
Copy link
Author

bcutter commented Jan 4, 2024

@GrumpyMeow are you reading/still maintaining this project?

@GrumpyMeow you seem to be active, unfortunately not in this repo. Can you please give us an update on this? Fixing this "does not work with bluetooth proxies" issue is a mandatory killer feature immediately resolving a ton of open issues.

@urosch
Copy link

urosch commented Jan 7, 2024

This is the log output from home assistant after trying to connect my sonicare to ha via esphome:
2024-01-07 12:00:28.419 INFO (SyncWorker_7) [homeassistant.util.package] Attempting install of sonicare-bletb==0.0.8 2024-01-07 12:01:28.647 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Init 2024-01-07 12:01:28.647 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: initialise 2024-01-07 12:01:28.647 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Connecting; RSSI: None 2024-01-07 12:02:11.702 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Init 2024-01-07 12:02:11.702 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: initialise 2024-01-07 12:02:11.702 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Connecting; RSSI: None 2024-01-07 12:03:29.214 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Init 2024-01-07 12:03:29.214 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: initialise 2024-01-07 12:03:29.214 WARNING (MainThread) [sonicare_bletb.sonicare_bletb] Philips Sonicare: Connecting; RSSI: None 2024-01-07 12:03:49.238 WARNING (MainThread) [aioesphomeapi.connection] esphome-web- @ 100.0.0.1: Connection error occurred: [Errno 104] Connection reset by peer 2024-01-07 12:03:49.238 INFO (MainThread) [aioesphomeapi.reconnect_logic] Processing unexpected disconnect from ESPHome API for esphome-web- @ 100.0.0.1 2024-01-07 12:03:49.251 INFO (MainThread) [aioesphomeapi.reconnect_logic] Successfully connected to esphome-web- @ 100.0.0.1 in 0.005s 2024-01-07 12:03:49.329 INFO (MainThread) [aioesphomeapi.reconnect_logic] Successful handshake with esphome-web- @ 100.0.0.1 in 0.078s

@adheaps
Copy link

adheaps commented May 2, 2024

Seems @GrumpyMeow has abandoned this project. Would love to see some progress on this. Is this something that the Home Assistant dev team would pick up? It appears to have some good interest from the community.

@bcutter
Copy link
Author

bcutter commented May 3, 2024

I don't think that is gonna happen. Usually a custom integration needs to prove it is "good enough" (like function in general, reliable, flexible in terms of reaction time for changes in core etc.) to become a core/default integration.

Very sad here's no progress, which makes this basically really great integration basically completely useless for most users. Sell Philips, get a Oral-B? Just kidding.

@jlipsit
Copy link

jlipsit commented Jul 6, 2024

Summary of Errors and Troubleshooting Steps for ESP32 Bluetooth Proxy with Sonicare BLE Toothbrush

Updated: I found that although it will connect to a BT Dongle directly connected to the controller, it does not reconnect reliably after the toothbrush goes to sleep. I have to RELOAD the integration when the brush is awake to get it to reconnect. It only stays connected to that "session" and then will not reconnect. Therefore I suspect the integration has some issues that are just more severe when used with a proxy. IS ANYONE USING THIS RELIABLY WITH A DIRECT CONNECTION TO A BT DONGLE?

I picked up a new Philips Sonicare and verified that it will not provision and connect when using a BT proxy, It will connect and operate properly when using a BT dongle connect to the Home Assistant Green controller.

Although the toothbrush is discovered successfully, when attempting to add it to HA, when using an ESP32 Bluetooth proxy the Sonicare BLE toothbrush disconnects with error messages indicating "Connection reset by peer" (Errno 104). This issue occurs consistently, preventing the ability to add it to HA.

I did a lot of troubleshooting............... Here are some of my logs and troubleshooting

ESP32 Device Log Extract:

BLE Connection Attempts and Errors:

First Connection Attempt:
Timestamp: [08:05:24]
Device MAC: D3:35:34:35:53:8C
Event:
[08:05:24] Attempting BLE connection
[08:05:27] ESP_GATTC_CONNECT_EVT
[08:05:27] ESP_GATTC_OPEN_EVT
[08:05:27] Connected
[08:05:36] Disconnecting
[08:05:36] ESP_GATTC_CLOSE_EVT

Second Connection Attempt:
Timestamp: [08:06:42]
Device MAC: 24:E5:AA:75:27
Event:
[08:06:42] Attempting BLE connection
[08:06:42] ESP_GATTC_CONNECT_EVT
[08:06:42] ESP_GATTC_OPEN_EVT
[08:06:56] ESP_GATTC_DISCONNECT_EVT, reason 8
[08:06:56] ESP_GATTC_CLOSE_EVT
[08:06:57] Attempting BLE connection
[08:06:58] ESP_GATTC_CONNECT_EVT
[08:06:58] ESP_GATTC_OPEN_EVT

Third Connection Attempt:
Timestamp: [08:07:26]
Device MAC: 24:E5:AA:75:27
Event:
[08:07:26] Attempting BLE connection
[08:07:33] ESP_GATTC_CONNECT_EVT
[08:07:33] ESP_GATTC_OPEN_EVT
[08:07:46] Disconnecting
[08:07:47] ESP_GATTC_CLOSE_EVT
[08:07:47] Attempting BLE connection
[08:07:48] ESP_GATTC_CONNECT_EVT
[08:07:48] ESP_GATTC_OPEN_EVT

Errors:
Timestamp: [08:06:42]
Error: hcif disc complete: hdl 0x0, rsn 0x3e
Timestamp: [08:06:56]
Error: gattc_conn_cb: if=3 st=0 id=3 rsn=0x8
Timestamp: [08:06:57]
Error: BTM_BleScan scan not active
Error: bta_dm_ble_scan stop scan failed, status=0x6
Timestamp: [08:07:26]
Error: hcif disc complete: hdl 0x0, rsn 0x3e
Timestamp: [08:07:46]
Error: GATTC_ConfigureMTU GATT_BUSY conn_id = 3
Error: hcif disc complete: hdl 0x0, rsn:0x13
Error: No pending command

Summary:
The ESP32 attempts to connect to the BLE device multiple times, experiencing intermittent success and errors such as disconnection events and scan failures. Each connection attempt and its outcome are logged with timestamps for detailed troubleshooting.

Successful Initial Connections:

  • The log shows successful connection attempts to the toothbrush's BLE device, identified by its MAC address (e.g., [24:E5:AA:75:27:D9]).
  • BLE events such as ESP_GATTC_CONNECT_EVT and ESP_GATTC_OPEN_EVT indicate that the ESP32 Bluetooth proxy is able to establish initial connections.
  • the signal strength appears adequate (Signal strength: -58 dB)

Frequent Disconnections:

  • The log contains several instances of disconnection events (ESP_GATTC_DISCONNECT_EVT), often followed by immediate reconnection attempts.
  • Disconnection reasons (rsn) vary but commonly include 0x16 and 0x3e.

Warnings and Errors:

  • Warnings such as Connection error occurred: [Errno 104] Connection reset by peer suggest that the connection is being unexpectedly terminated.
  • There are several instances of hcif disc complete: hdl 0x0, rsn 0x16 indicating that the disconnection is being completed by the Bluetooth host.

Troubleshooting Steps Taken:

Configuration Adjustments:

Adjusted esp32_ble_tracker scan parameters to optimize BLE scanning:

esp32_ble_tracker:
  scan_parameters:
    interval: 320ms
    window: 160ms
esp32_ble_tracker:
  scan_parameters:
    interval: 160ms
    window: 80ms

Power Supply Verification:

Ensured that the ESP32 is connected to a stable power source to avoid power-related disconnections.
Interference Minimization:

Reduced potential Bluetooth and Wi-Fi interference by positioning the ESP32 and Sonicare toothbrush closer together and away from other electronic devices.

Firmware and Software Updates:

Confirmed that all firmware and software (ESPHome, Home Assistant, and ESP32 firmware) are updated to the latest versions available at the time of testing.

Core
2024.7.1
Supervisor
2024.06.2
Operating System
12.4
Frontend
20240705.0

Logger Configuration:

Enabled detailed logging to capture more granular details for debugging:

logger:
  level: debug
  logs:
    esp32_ble_client: debug

Alternative Connectivity Test:

Verified that the Sonicare toothbrush connects successfully using a Bluetooth dongle plugged directly into the Home Assistant Green controller, indicating the issue is specific to the ESP32 Bluetooth proxy.

image

@bcutter
Copy link
Author

bcutter commented Jul 6, 2024

Great work! For sure took a loooooot of time. How should we use those perfect information (you mentioned "the ESP home guys need to look at this issue")?

Maybe someone can ping them?

Another note: I also use Shelly's as bluetooth proxies, with the same (not working) results as with a ESP home powered bluetooth proxy. Shelly are also based on ESP, but not ESP Home - just as a small note.

@jlipsit
Copy link

jlipsit commented Jul 6, 2024

Unfortunately, I don't think they will look at it until someone takes over this integration and reviews the code for possible errors. It's sad because the Oral B is very expensive and the Sonicare has excellent hardware and is very affordable.

@jlipsit
Copy link

jlipsit commented Jul 6, 2024

I found that although it will connect to a BT Dongle directly connected to the controller, it does not reconnect reliably after the toothbrush goes to sleep. I have to RELOAD the integration when the brush is awake to get it to reconnect. It only stays connected to that "session" and then will not reconnect. Therefore I suspect the integration has some issues that are just more severe when used with a proxy. IS ANYONE USING THIS RELIABLY WITH A DIRECT CONNECTION TO A BT DONGLE?_

@edwardtfn
Copy link
Contributor

IS ANYONE USING THIS RELIABLY WITH A DIRECT CONNECTION TO A BT DONGLE?

Unfortunately, no. 😩

@jlipsit
Copy link

jlipsit commented Jul 6, 2024

IS ANYONE USING THIS RELIABLY WITH A DIRECT CONNECTION TO A BT DONGLE?

Unfortunately, no. 😩

So just to clarify, you have it connected to a BT dongle directly, but it is not reliable?

@edwardtfn
Copy link
Contributor

Exactly. In the end, it's not useful.

@Dodoooh
Copy link

Dodoooh commented Aug 28, 2024

is there any good news to get this up and running?

@bcutter
Copy link
Author

bcutter commented Aug 28, 2024

No. The author of this integration doesn't seem to be active in any way. This makes us (potential) users grumpy and leaves us with a non-working integration. Completely useless.

@v6ak
Copy link

v6ak commented Nov 30, 2024

I remember having similar issues when implementing QuietDrift for SwitchBot Curtain 3. Originally, it was a separate service called via HTTP from HA. However, I got into connection issues similar to those. I implemented various reconnecting mechanisms, but it was hard to make it working in long term. Then, I rewrote it as a custom component and let HA to manage the BT connection, which has fixed the connection issues.

My original code was obtaining the device object from bleak_retry_connector.get_device. And this this custom component does something similar:

ble_device = bluetooth.async_ble_device_from_address(
hass, address.upper(), True
) or await get_device(address)

Well… It isn't exactly the same. It tries to use bluetooth.async_ble_device_from_address first. However, when the device isn't reachable, it returns None, which forces a fallback to bleak_retry_connector.get_device. And it is quite common that the device is unreachable. In this case, bleak_retry_connector.get_device is likely to also fail, but it doesn't have to, as it is called somewhat later, and apparently can wait a bit. In my logs, I've seen an error from bleak_retry_connector, which suggests that this sometimes happens.

The code is in async_setup_entry, and it is the only place where async_ble_device_from_address/get_device is called, which has few consequences:

  • It usually fails on startup, unless the toothbrush is reachable. (It is rarely the case.)
  • It seems HA retries later when it discovers such device.
  • Once the connection is lost, there is probably no mechanism to recover from that. HA will probably still consider the setup entry as valid, but the component doesn't seem to have a mechanism for reconnecting.

Not sure about async_ble_device_from_address, but I am pretty sure that bleak_retry_connector.get_device retries just in the first connection. Once the connection is lost, the returned object doesn't retry.

Initially, I am removing the get_device fallback and will see how it affects the behavior. I am not sure why it was added, as 34508e3 doesn't explain much.

@v6ak
Copy link

v6ak commented Nov 30, 2024

Few more findings:

First, it has connected to the toothbrush even with all BT adapters disabled, leaving only BT proxies.

Second, it has still issues with disconnecting. Looking more about the code of this repo, the library and the documentation, it seems that the component (and/or its libraries) is responsible for reconnections. There is however some mechanism, but seemingly incomplete:

  1. The library has _reconnect method, which is called from _disconnected and from itself. However, calling from itself happens only in case of except BleakNotFoundError:, not in case of other errors. But the errors are more diverse.
  2. The component listens for new device with the toothbrush's address and calls set_ble_device_and_advertisement_data, which, aside of logging, just sets properties, but doesn't call _reconnect. Which means it cannot save us when the reconnect loop is broken.

Looking from 10 feets:

  1. Not sure if bleak_retry_connector.get_device is to blame. It shouldn't be needed, maybe it was added as an attempt to fix something (the megacommit 34508e3 doesn't tell us much). Now, it seems to just add complexity and I'll probably keep it removed.
  2. The reconnects depend on polling (quite frequent, 0.25s), but it's a bit weird to poll for a toothbrush, which is offline most of the time.
  3. The polling frequency will affect what kind of issues we face. Frequent polling increases likelihood of errors other than BleakNotFoundError (that stop the polling). Less frequent polling increases likelihood that HA will not connect within the short window when toothbrush is online.

What to do:

  1. First and foremost, the _async_update_ble should trigger reconnect ASAP. (Not sure what to do when it is still connected.) So we woulnd't rely on polling.
  2. We should also register a disconnect handler which stops the polling when toothbrush is disconnected. This would make the polling effectively disabled (without actually removing the polling code from the library).
  3. Bonus: don't rely on toothbrush being available on startup (in async_setup_entry).

I'll probably do it later, it doesn't look that hard.

EDIT: I got a bit struggles with the callbacks, HA's documentation isn't perfect. But maybe I was reinventing the wheel – it looks like ActiveBluetoothDataUpdateCoordinator has already implemented what I need.

@bcutter
Copy link
Author

bcutter commented Nov 30, 2024

@v6ak Wow, impressive (as always when users see devs talking and doing their magic 😀).

Sounds like maybe Christmas takes place a bit earlier this year: toothbrush working with BT proxies sounds so 👍

@simbalasim
Copy link

@v6ak
Wow, that sounds really promising. I'm not a developer either, but that sounds like you have found at least a direction how to progress further. Much appreciated
Really great that you're taking this on and investing your time. Many thanks for that 😃,

I'm currently working with very unreliable workournds,. when the toothbrush connects to a tablet, the Soniccare app simply opens. Not particularly fancy ^^

Unfortunately I don't know coding, but if I can help e.g. with testing, please let me know.

@v6ak
Copy link

v6ak commented Nov 30, 2024

Well, not sure how to proceed. I've tried multiple ways to discover the device:

  • bluetooth.async_register_callback
  • ActiveBluetoothDataUpdateCoordinator
  • bluetooth.async_get_scanner

Expected results: the device gets discovered when I make the toothbrush active (move, brushing, briefly after brushing, briefly after charging), so I can connect it.

Actual results: the device gets discovered immediately and seems to never disappear. However, I don't get a callback when the device is actually activated.

I feel like I am missing something trivial, but not sure what…

@jlipsit
Copy link

jlipsit commented Dec 1, 2024

With all my testing, I got the impression that there was some bug in the brush itself. I just threw mine in the trash this week and purchased 4 Oral B Series 4 toothbrushes off eBay. Great brush and about $50 bucks new on eBay if you are patient. The are rock solid in Home Assistant.

Not Running View
image

Running View
image

@u20p17
Copy link

u20p17 commented Dec 1, 2024

@v6ak : thank you very much for trying to solve the issue! Looking forward to test your fixes in the future with my philips toothbrush 👌

Regarding you missing callback: maybe you could as in the discord channel of HomeAssistant in the dev area. Maybe you get some hints 👍

@adheaps
Copy link

adheaps commented Dec 1, 2024

@v6ak - I'd like to thank you as well. So happy to see someone trying to solve this issue. Truly appreciate your efforts on this.

@v6ak
Copy link

v6ak commented Dec 1, 2024

I was trying to perform a deeper rewrite of the BT handling, but ended with just conservative changes:

  • Got rid of get_device fallback when HA's API fails. Not 100% sure about its impact, but it should be unneeded.
  • When the toothbrush reappears, I force reconnect even if the original reconnect loop (which seems to be unreliable) has died.
  • CI, not directly relevant to end users

I don't think it will be 100% reliable, but it might be reliable enough for some uses, including my needs (battery monitoring and keeping the charge about 50 %). My adjustments in reconnect will probably work only after longer inactivity, which might be enough for typical use (brushing twice a day).

Because testing needs longer inactivity, it is not much tested, but if you want to try it anyway, it's there: https://github.com/v6ak/sonicare-ble-hacs

Some issues that aren't fixed:

  • When HA boots, the toothbrush will appear as failed until it connects.
  • Reconnects might be a bit aggressive, potentially delaying communication with others devices.

How (re)connecting works, what are the challenges?

It seems to be quite easy to initiate the connection to the toothbrush. However, you probably don't want to press a button (within the short time-frame) in order to do that. It should be done automatically.

The toothbrush is apparently offline for most of the time, so it is crucial to detect when it becomes online. Also, it is crucial to detect is ASAP, because the time when you can connect is quite short.

One could try to connect periodically (so called polling). The polling would have to be quite frequent (as the time for connection is quite short). This would not only take CPU (maybe not that much), it also uses Bluetooth communication. Depending on your BT adapter and other BT devices, you might reach the limit of maximum connected devices. This addon (well, the sonicare-blebt library) does this partially, but it seems to break in long term.

The other way to do it is to somehow detect when a toothbrush is available, just by being passive and waiting for some indication. BT devices announce their presence (if they are configured to be visible), and it seems to be also the case of Sonicare toothbrush when it starts being active (brushing, charging ends, brush moves, …). However, apparently, I can't see all the beacons. The HA Bluetooth API documentation suggests that you probably will not receive two such notification in a short succession:

To get a callback when the Bluetooth stack can no longer see a device, call the bluetooth.async_track_unavailable API. For performance reasons, it may take up to five minutes to get a callback once the device is no longer seen.

Yes, this is about unavailability notification, but availability notifications probably work in a similar manner. When HA doesn't see the device, it takes a time to consider it unavailable. When a beacon from the device is received, HA probably doesn't notify about its availability, as it didn't consider the device to be unavailable. In my testing, it looked like there is some longer period than just five minutes, but I might got something wrong or misunderstand something.

Possible workaround for missing the availability notification

If my changes aren't enough and HA doesn't detect the presence of the toothbrush enough, we could add a service that would connect the toothbrush when called. It would be up to user to call it when needed. This could work automatically in some setups, e.g.:

  1. I'll assume that the toothbrush is usually on a charger and the charger is connected through a smart socket, which is off most of the time.
  2. On some event, the smart socket would briefly (for 5 seconds or so) turn on and then off, so the toothbrush becomes active.
  3. As HA is aware when this happens, some automation could call the service.

I hope this will not be needed, though.

@u20p17
Copy link

u20p17 commented Dec 2, 2024

@v6ak : thanks again! today in the morning I briefly tried to connect my sonicare via a bluetooth proxi to HA, but sadly I couldn't connect. I didn't have time to check logs, but in theory the connection via bluetooth proxis should work (with your branch)?

@v6ak
Copy link

v6ak commented Dec 2, 2024 via email

@v6ak
Copy link

v6ak commented Dec 2, 2024

It seems that the issue with device discovery was independently described by GrumpyMeow. Anyway, it looks like the connection to the toothbrush is successful if and only if the last attempt is old enough (EDIT) or fresh enough, but not few minutes after the last attempt. Not perfect, probably good-enough for me. Not sure if we can do much about it without changing the HA core, except adding a service for forcing a reload.
EDIT: Maybe bluetooth.async_set_fallback_availability_interval(hass, address, 1.0) or something similar will do the trick.
EDIT2: Maybe it is not that simple. there seem to be two different default timeouts. And the timeout for connectable devices doesn't seem to be overridable.
EDIT4: Maybe async_rediscover_address will do the trick.

What's not that good is that only some entities seem to be updated. Handle time seems to be updated, but battery state doesn't. This is kinda weird, as both seem to be implemented in the very same way. I hope I can work around by full reinitialization.

EDIT3: I've also looked on active vs. passive scanning. I think that passive scanning would be faster and enough for the toothbrush connection. However, because HA actually ignores the mode for now, I'll keep active scanning, as I cannot test if passive scanning is enough and it has currently no benefit.

@v6ak
Copy link

v6ak commented Dec 2, 2024

Just pushed a new version:

  • Doesn't fail when toothbrush isn't available during boot.
  • Availability notification now seem to be reliable, thanks to async_rediscover_address.
  • The library should no longer poll for toothbrushes (it doesn't reconnect without an advertisment). Benefit: it doesn't occupy connection slots.
  • Attempt to work around missing battery info by reinitializing SonicareBLETB, maybe not successful.

Known issues that remain:

  • Battery status isn't always updated
  • In some cases, default values (e.g. battery status = 0) might propagate to entities
  • Values aren't stored after HA reboot

@v6ak
Copy link

v6ak commented Dec 2, 2024

Well, I started getting issues with my BLE proxy. I have just a single proxy. It fails with the following error message:

2024-12-02 14:39:52.131 ERROR (MainThread) [homeassistant] Error doing job: Fatal error: protocol.data_received() call failed. (None)
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 1017, in _read_ready__data_received
    self._protocol.data_received(data)
  File "aioesphomeapi/_frame_helper/noise.py", line 205, in aioesphomeapi._frame_helper.noise.APINoiseFrameHelper.data_received
  File "aioesphomeapi/_frame_helper/noise.py", line 364, in aioesphomeapi._frame_helper.noise.APINoiseFrameHelper._handle_frame
  File "aioesphomeapi/connection.py", line 956, in aioesphomeapi.connection.APIConnection.process_packet
  File "/usr/local/lib/python3.12/site-packages/bleak_esphome/backend/scanner.py", line 42, in async_on_raw_advertisements
    self._async_on_advertisement(
  File "src/habluetooth/base_scanner.py", line 356, in habluetooth.base_scanner.BaseHaRemoteScanner._async_on_advertisement
  File "src/habluetooth/base_scanner.py", line 389, in habluetooth.base_scanner.BaseHaRemoteScanner._async_on_advertisement
TypeError: Expected unicode, got list
2024-12-02 14:39:52.142 WARNING (MainThread) [aioesphomeapi.connection] <name of BLE proxy> @ <IP address of BLE proxy>: Connection error occurred: Expected unicode, got list

Then, the device with BLE proxy keeps almost offline. It doesn't update sensor data and it cannot connect BT devices, but it can propagate advertisments and a button press.

Maybe I have an outdated software on the BLE proxy. I'll see if update fixes something.

@v6ak
Copy link

v6ak commented Dec 2, 2024

Investigation of BLE proxies crashes

ESPhome upgrade didn't fix it.

The weirdest part of the error is that it comes from this line (not sure if the version perfectly matches, but at least the specific line is the same in HA Docker image):

https://github.com/Bluetooth-Devices/habluetooth/blob/7526057b1839b9929a802600fdb5c117465ea1ea/src/habluetooth/base_scanner.py#L389

How can this line cause a TypeError?

Temporary workaround

I've disabled the async_rediscover_address call, which seems to cause some wrong state somewhere. Also, this call is probably not much frequently used, so it can be less tested. It seems that it has resolved the issues with BLE proxy crashes.

The drawback is that the toothbrush doesn't reconnect that reliably. Again, this is likely not a big issue in common usage scenarios (brushing twice a day), but it can be annoying when testing.

@v6ak
Copy link

v6ak commented Dec 2, 2024

Just a timeline what happens when you activate toothbrush:

  1. You activate a toothbrush (move it, brush teeth, stop charging, …).
  2. Toothbrush announces availability.
  3. HA detects the toothbrush availability.
  4. HA connects to the toothbrush and reads some data.
  5. Toothbrush appears disconnected (lights are off).
  6. Toothbrush appears disconnected in the addon. (It can be about a minute or two later than previous step.)
  7. Toothbrush appears unavailable in Home Assistant. (It can be about 7 minutes later than the previous step! Moreover, if you activate toothbrush within this period, you probably prolong it.)

Between 6 and 7, the toothbrush is disconnected, but Home Assistant still considers it to be available. This means that when HA sees a new advertisment, it doesn't think the toothbrush becomes available. It thinks that the toothbrush is still available. As a result, it doesn't notify the addon. So, when user attempts to wake the toothbrush within this period, HA doesn't forward the advertisment to the addon. Even worse, it probably resets a timeout, so the user has actually to wait even more. (I think it is this 5min timeout).

Attempts to resolve the issue:

  1. bluetooth.async_set_fallback_availability_interval(hass, address, 1.0) – doesn't do anything
  2. bluetooth.async_rediscover_address(self.hass, self.address) when disconnected – it causes the addon to receive proper notification when the toothbrush is connected again (even between 6 and 7), but when the addon tries to reconnect between 6 and 7, it causes some weird crash of BLE proxy. I need to restart both the BLE proxy and Home Assistant in order to recover from it. Maybe it would work without BLE proxies. Weird fact: It seems that even after async_rediscover_address, the device isn't considered as unavailable.
  3. Don't care about it. In typical scenarios, you probably don't need to use the toothbrush again within ~ 7 minutes.

@Dodoooh
Copy link

Dodoooh commented Dec 3, 2024

Hey @v6ak

Thank you so much for your effort—it’s brilliant! I tried setting it up today, but unfortunately, it doesn’t seem to work for me. The toothbrush does appear, but as soon as I try to add it, it just keeps loading endlessly.

How did you manage to get it working? I’ve tried everything: adding it after charging, during brushing, while shaking it, spinning in circles… nothing seems to work.

What I also noticed is that Shelly BT proxies don’t seem to function in this case (though they work fine for everything else and are set to active). To troubleshoot, I placed an ESPHome BT Proxy in the bathroom.

If there’s any log or information I can provide, please let me know—I’m happy to help in any way I can!

But really, thanks again! I’d love to get this integration up and running.

@PV-Web
Copy link

PV-Web commented Dec 3, 2024

Awesome to see this topic alive again! I will soon test it with shelly BT proxy if it works on my end. Unfortunately I do not have any other bluetooth proxies available to test it with.

@v6ak
Copy link

v6ak commented Dec 4, 2024

My effort was focused on reliability of connection after the toothbrush is added, not on adding the toothbrush. However, I've tried to remove my toothbrush and add it again while having all BT adapters (except BT proxies) disabled. So, it must have connected through the BT proxy and it succeeded. (I have just one BT proxy.)

Reliability of adding a new toothbrush might have been improved as a side effect, because the addon no longer requires successful connection for initialization. But I am not sure.

If you still have issues with adding the toothbrush to HA:

  • Be aware that the opportunity to connect the toothbrush is usually quite short.
  • When brushing, the opportunity to connect might be longer, but I haven't tried to connect it during brushing.
  • However, I usually wake the toothbrush just by charging it for few seconds. Because my toothbrush stands on a charger, which is powered through a smart socket, I can do this easily at distance.
  • You might want to disable BT on your phone, as the phone might also try to connect to the toothbrush.
  • Usual advices: direct visibility, short distance…

@Dodoooh If you can share some logs (related to Sonicare), you are welcome. Please try it with the newest version.


Current known issues:

  • Battery status isn't always reported. This looks a bit random. However, since I've seen the same issue with the official app, I am not sure if I can do anything about it.
  • Sometimes, BLE proxy kind of crashes (as described at Not working with Bluetooth Proxies (ESP32 based) #14 (comment) ) and I have to restart both the proxy and HA. This looks like issue in HA and/or related software (ESPHome etc.). I guess I could report an issue, but reproduction steps currently require a quite specific hardware (Sonicare toothbrush). If I had a reproduction steps for a more common hardware (e.g., Android phone or Linux-based PC), it would allow me to create a better report.
  • When some value isn't loaded, you see a zero-like value, not "unavailable".
  • After a toothbrush is disconnected, there is a short period (few minutes) when the toothbrush cannot connect again, as described at Not working with Bluetooth Proxies (ESP32 based) #14 (comment) .

@v6ak
Copy link

v6ak commented Jan 18, 2025

Observation: Battery is reported again not only HA reboot, but also after ESP32 reboot. Maybe after any reconnection between ESPHome and HA. (Would router reboot also do the trick?)

However, I am not sure if I'll continue with working on the fork:

  1. It already somehow works for me, although it isn't perfect.
  2. The remaining issues I am aware of don't seem to be easy to debug/solve. Still, I can somehow support someone who wants further develop my fork, if it doesn't take much time. That is, I can share my knowledge learned, but probably won't participate in deep debugging.
  3. There is an alternative solution for ESP32 users: https://community.home-assistant.io/t/philips-sonicare-integration-for-bluetooth-toothbrushes/178229/27

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests