fix(ble): Retry ConnectDevice() on every connection to prevent BR/EDR fallback

Fixes "br-connection-canceled" and "Operation already in progress" errors
caused by BlueZ attempting Classic Bluetooth (BR/EDR) instead of BLE (LE).

Problem:
- ConnectDevice() with AddressType="public" forces LE-only connections
- Previously only tried once (has_connect_device is None check)
- After first failure, ALL future connections skipped ConnectDevice()
- Fell back to client.connect() which may trigger BR/EDR on dual-mode adapters

Solution:
- Changed condition from "is None" to "!= False"
- Now retries ConnectDevice() on every connection (unless definitively unavailable)
- Improved error handling:
  * AttributeError → method doesn't exist, disable permanently
  * Other exceptions → transient failure, retry next time
- Elevated log level to INFO for successful LE connections

Impact:
- Eliminates BR/EDR connection attempts on BLE-only devices
- Fixes immediate disconnects after pairing
- Prevents connection blacklisting due to protocol mismatch

Tested on: Raspberry Pi with BlueZ 5.66 + experimental mode
This commit is contained in:
torlando-tech 2025-11-06 00:36:14 -05:00
commit 7809d9c5ca

View file

@ -756,14 +756,19 @@ class LinuxBluetoothDriver(BLEDriverInterface):
# Try LE-specific connection if BlueZ >= 5.49 # Try LE-specific connection if BlueZ >= 5.49
le_connection_attempted = False le_connection_attempted = False
if self.bluez_version and self.bluez_version >= (5, 49) and self.has_connect_device is None: if self.bluez_version and self.bluez_version >= (5, 49) and self.has_connect_device != False:
try: try:
await self._connect_via_dbus_le(address) await self._connect_via_dbus_le(address)
le_connection_attempted = True le_connection_attempted = True
self._log(f"LE-specific connection initiated for {address}", "DEBUG") self._log(f"LE-specific connection initiated for {address}", "INFO")
except Exception as e: except AttributeError as e:
self._log(f"ConnectDevice() unavailable, falling back to standard connection", "DEBUG") # ConnectDevice method doesn't exist in this BlueZ version
self._log(f"ConnectDevice() method not available: {e}", "WARNING")
self.has_connect_device = False self.has_connect_device = False
except Exception as e:
# ConnectDevice exists but failed - retry on next connection
self._log(f"ConnectDevice() failed (will retry): {e}", "WARNING")
# Don't set has_connect_device to False - allow retry
# Create BleakClient # Create BleakClient
client = BleakClient(address, disconnected_callback=disconnected_callback, timeout=self.connection_timeout) client = BleakClient(address, disconnected_callback=disconnected_callback, timeout=self.connection_timeout)