Skip to content

BleakClient.connect() only succeeds when timeout parameter is set (ServicesResolved never arrives otherwise) #1841

@vgamero

Description

@vgamero

I tried this simple code to connect to a Polar H10. Using a BleakClient without passing a timeout parameter, the connection almost never succeeds it ends with a TimeoutError. However, when setting timeout=15–20, the connection becomes stable and ServicesResolved is reached successfully. The documentation mentions that setting a timeout is not recommended, but without it, the device never completes service discovery.

def on_disconnect(client: BleakClient):
    """Triggered automatically when the device disconnects."""
    print("Device has been disconnected.")


async def connect_device(client: BleakClient) -> BleakClient | None:
    """Establish a BLE connection using a BleakClient instance."""
    try:
        # Connection only succeeds reliably on BlueZ when timeout is explicitly set
        await client.connect(timeout=20)
    except BluetoothConnectionError as e:
        print(f"Connection error ({type(e).__name__}): {e}")
        return None

    if client.is_connected:
        print("Device connected successfully.")
        return client

    print("Connection failed after connect().")
    return None


async def disconnect_device(client: BleakClient):
    """Controlled disconnection."""
    if client.is_connected:
        try:
            await client.disconnect()
            print("Device disconnected successfully.")
        except Exception as e:
            print(f"Error while disconnecting ({type(e).__name__}): {e}")
    else:
        print("No active connection to disconnect.")


async def hr_monitor():
    devices = await scan_devices(filter_name="polar", show=True)
    if not devices:
        return

    polar = devices[0]
    client = BleakClient(polar, disconnected_callback=on_disconnect)
    print(f"Attempting to connect to {polar.name}...")

    client = await connect_device(client)
    if not client:
        print("Could not connect to the device.")
        return

    try:
        while True:
            await aio.sleep(1)
    finally:
        await disconnect_device(client)
        print("Disconnected by user.")


if __name__ == "__main__":
    try:
        aio.run(hr_monitor())
    except KeyboardInterrupt:
        print("\nStopped by user.")

Environment:

  • OS: Debian 12
  • BlueZ: 5.66
  • Python: 3.10
  • Bleak: 1.1
  • Peripheral: Polar H10 (firmware up to date)

1- Scrip Error:
Traceback (most recent call last):
File ".../bleak/backends/bluezdbus/client.py", line 355, in connect
await self._get_services(
File ".../bleak/backends/bluezdbus/client.py", line 713, in _get_services
self.services = await manager.get_services(
File ".../bleak/backends/bluezdbus/manager.py", line 687, in get_services
await self._wait_for_services_discovery(device_path)
File ".../bleak/backends/bluezdbus/manager.py", line 841, in _wait_for_services_discovery
done, _ = await asyncio.wait(...)
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File ".../bleak/init.py", line 580, in connect
await self._backend.connect(self._pair_before_connect, **kwargs)
File ".../bleak/backends/bluezdbus/client.py", line 156, in connect
async with async_timeout(timeout):
File ".../async_timeout/init.py", line 265, in aexit
raise asyncio.TimeoutError
asyncio.exceptions.TimeoutError

What I checked:

  • D-Bus: Connected=True arrives, but ServicesResolved=True does not arrive in the failing case.
  • HCI/ATT (Wireshark): link up + MTU exchange are visible; when it fails, I don’t see the expected Read By Group Type Response (0x11) following Read By Group Type (0x10), so BlueZ appears to wait indefinitely for service discovery to finish. With timeout=20, the 0x11 responses show up and discovery completes.

Questions / ask

1- Is this a known BlueZ-backend quirk that requires an explicit timeout for some peripherals?
2- Possibly related to: #1806 (service discovery/ServicesResolved behavior)?

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