Skip to content

Alternative integration with event-driven approach and connection improvements #18

@Koky05

Description

@Koky05

Hi @GrumpyMeow and community,

I've been working on a Sonicare integration for my two Sonicare Kids toothbrushes (HX6352/11 and HX6322/12) and wanted to share observations and an alternative approach that addresses several issues discussed here.

Key Observations

BLE Behavior Differences Between Devices

  • Device "Max" (24:E5:AA:7A:52:A7): Previously connected successfully when just "on" (display showing, not brushing)
  • Device "Ema" (24:E5:AA:80:37:CA): Only accepts connections during active brushing (motor running)
  • This suggests firmware differences even between the same model line

Connection Failure Counter Problem

Failed BLE connection attempts increment habluetooth's internal failure counter. A high failure count can block subsequent detection callbacks entirely, preventing the integration from receiving notifications when the device reappears. This is likely the root cause of the "stops working after first session" issue reported in #14.

Toothbrush Auto-Off

Sonicare Kids display turns off after a short timeout when not brushing. BLE advertising stops when the display is off. The brushing window is only ~2 minutes.

Alternative Approach

I've published an alternative integration at Koky05/ha-sonicare-battery that takes a different approach:

Feature This Integration My Alternative
Architecture Persistent connection + polling Event-driven (no polling)
Startup Blocks if device offline Never blocks, waits for detection
Reconnection Relies on library reconnect loop Fresh BleakClient on each detection
Rate limiting No Yes (30s minimum between reads)
State restoration No Yes (RestoreEntity)
Failure counter Accumulates Minimized (single attempt per detection)
BLE library sonicare-bletb (custom) bleak + bleak_retry_connector (standard)
HACS/Hassfest N/A Passing CI

Key Design Decisions

  1. No persistent connection — Creates a fresh BleakClient for each read, avoiding the reconnection issues identified by @v6ak in Anyway to decrease the startup time of the integration? Stalls and warnings if a previously setup brush is in sleep/offline/dead #11
  2. Event-driven via bluetooth.async_register_callback — Only acts when the device is actually detected
  3. Rate limiting — Prevents BLE spam during brushing sessions
  4. RestoreEntity — Sensors keep their last known values after HA restart, which is essential since the device is offline 99% of the time
  5. No startup dependency — Integration sets up even when the toothbrush is off

What Works Reliably

  • Battery reading during active brushing sessions
  • RSSI and Last Seen tracking on every BLE advertisement
  • State restoration across HA restarts

What Doesn't Work Reliably

  • Reading proprietary characteristics (Handle State, Brushing Time, Mode, Intensity) — these are read but not exposed as sensors due to inconsistent availability across devices

Credits

This work was informed by the excellent analysis from @v6ak (#11 comments) on the connection management issues, and of course by your original integration which established the Sonicare BLE characteristic UUIDs.

The alternative integration is available via HACS: https://github.com/Koky05/ha-sonicare-battery

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions