Skip to content

backends/corebluetooth: clear notify callbacks on disconnect#1997

Closed
miguel-neto-andrade wants to merge 1 commit into
hbldh:developfrom
miguel-neto-andrade:fix-corebluetooth-notify-state-on-disconnect
Closed

backends/corebluetooth: clear notify callbacks on disconnect#1997
miguel-neto-andrade wants to merge 1 commit into
hbldh:developfrom
miguel-neto-andrade:fix-corebluetooth-notify-state-on-disconnect

Conversation

@miguel-neto-andrade

@miguel-neto-andrade miguel-neto-andrade commented Jun 12, 2026

Copy link
Copy Markdown

Fixes #1969.

On macOS, calling start_notify() after disconnecting and reconnecting with the same BleakClient raises ValueError("Characteristic notifications already started").

CoreBluetooth stops notifications at the OS level on disconnect, but the PeripheralDelegate is reused on reconnect (BleakClientCoreBluetooth.connect() only creates a new one when self._delegate is None), so the stale entries in _characteristic_notify_callbacks / _characteristic_notification_discriminators survive the disconnect and trip the guard in start_notifications(). This matches the root cause analysis in the issue comments.

Changes:

  • Add PeripheralDelegate.clear_notify_callbacks() and call it from the client's disconnect_callback, alongside the existing future cleanup.
  • Add tests/integration/test_issue_1969.py (connect → start_notify → disconnect → reconnect with the same client → start_notify), following the existing bumble-based test_issue_* pattern. It is CoreBluetooth-only via skipif, since BlueZ tracks notification state at the D-Bus level and is unaffected.
  • Changelog entry under Unreleased.

poe lint, poe typecheck and the unit tests pass locally on macOS.

Verified on real hardware (macOS, Apple Silicon, BlueNRG-based peripheral): on develop the second start_notify() after reconnecting with the same client instance raises ValueError("Characteristic notifications already started"); with this branch the same connect → notify → disconnect → reconnect → notify sequence succeeds.

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 25.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.42%. Comparing base (ae2f589) to head (ee079d3).

Files with missing lines Patch % Lines
bleak/backends/corebluetooth/PeripheralDelegate.py 33.33% 2 Missing ⚠️
bleak/backends/corebluetooth/client.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1997      +/-   ##
===========================================
- Coverage    52.45%   52.42%   -0.03%     
===========================================
  Files           43       43              
  Lines         4097     4101       +4     
  Branches       504      504              
===========================================
+ Hits          2149     2150       +1     
- Misses        1817     1820       +3     
  Partials       131      131              
Flag Coverage Δ
bluez-integration-py310 39.11% <0.00%> (-0.04%) ⬇️
bluez-integration-py311 39.11% <0.00%> (-0.04%) ⬇️
bluez-integration-py312 39.11% <0.00%> (-0.04%) ⬇️
bluez-integration-py313 39.11% <0.00%> (-0.04%) ⬇️
bluez-integration-py314 37.60% <0.00%> (-0.04%) ⬇️
macos-latest-py310 20.04% <25.00%> (+<0.01%) ⬆️
macos-latest-py311 20.04% <25.00%> (+<0.01%) ⬆️
macos-latest-py312 20.04% <25.00%> (+<0.01%) ⬆️
macos-latest-py313 20.04% <25.00%> (+<0.01%) ⬆️
macos-latest-py314 19.85% <25.00%> (+<0.01%) ⬆️
ubuntu-latest-py310 23.92% <0.00%> (-0.03%) ⬇️
ubuntu-latest-py311 23.92% <0.00%> (-0.03%) ⬇️
ubuntu-latest-py312 23.92% <0.00%> (-0.03%) ⬇️
ubuntu-latest-py313 23.92% <0.00%> (-0.03%) ⬇️
ubuntu-latest-py314 22.03% <0.00%> (-0.03%) ⬇️
windows-latest-py310 18.70% <0.00%> (-0.02%) ⬇️
windows-latest-py311 18.70% <0.00%> (-0.02%) ⬇️
windows-latest-py312 18.70% <0.00%> (-0.02%) ⬇️
windows-latest-py313 18.70% <0.00%> (-0.02%) ⬇️
windows-latest-py314 18.42% <0.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

CoreBluetooth stops notifications at the OS level when a peripheral
disconnects, but the PeripheralDelegate is reused when the same client
reconnects, so the stale entries in _characteristic_notify_callbacks
made a subsequent start_notify() raise ValueError("Characteristic
notifications already started").

Clear the notification bookkeeping in the disconnect callback so that
notifications can be started again after reconnecting.

Fixes #1969.
@miguel-neto-andrade miguel-neto-andrade force-pushed the fix-corebluetooth-notify-state-on-disconnect branch from ee079d3 to 9fa1f71 Compare June 12, 2026 20:00
@dlech

dlech commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

I'm not a fan of the non-integration tests that are testing the implementation details. They don't check if it actually works with the OS Bluetooth stack and real hardware, so just give a false sense of things working correctly.

@miguel-neto-andrade miguel-neto-andrade closed this by deleting the head repository Jun 12, 2026
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

Successfully merging this pull request may close these issues.

BleakClient.stop_notify() documentation seems not relevant for MAC OS

2 participants