{"id":3908,"library":"bleak","title":"Bleak: Bluetooth Low Energy Client","description":"Bleak (Bluetooth Low Energy platform Agnostic Klient) is an asynchronous, cross-platform Python library that acts as a GATT client. It enables scanning for BLE devices, connecting to them, and communicating by reading/writing GATT characteristics and descriptors, and subscribing to notifications/indications. Bleak is actively maintained, with the current version being 3.0.1, and typically releases updates as needed for bug fixes and new features.","status":"active","version":"3.0.1","language":"en","source_language":"en","source_url":"https://github.com/hbldh/bleak","tags":["bluetooth","ble","iot","hardware","asyncio","gatt"],"install":[{"cmd":"pip install bleak","lang":"bash","label":"Install stable release"}],"dependencies":[],"imports":[{"symbol":"BleakScanner","correct":"from bleak import BleakScanner"},{"symbol":"BleakClient","correct":"from bleak import BleakClient"},{"symbol":"BleakError","correct":"from bleak.exc import BleakError"},{"symbol":"BleakGATTProtocolError","correct":"from bleak.exc import BleakGATTProtocolError"},{"note":"Pre-v3.0.0 specific GATT errors on BlueZ backend; now wrapped by BleakGATTProtocolError.","symbol":"BleakDBusError","correct":"from bleak.exc import BleakDBusError"}],"quickstart":{"code":"import asyncio\nfrom bleak import BleakScanner, BleakClient\n\n# Replace with the actual address of your BLE device\n# For macOS, this might be a UUID. For Linux/Windows, a MAC address.\n# You can find the address by running the discovery part first.\nDEVICE_ADDRESS = \"XX:XX:XX:XX:XX:XX\" # Example for a generic device\nSERVICE_UUID = \"0000180f-0000-1000-8000-00805f9b34fb\" # Battery Service UUID\nBATTERY_LEVEL_CHAR_UUID = \"00002a19-0000-1000-8000-00805f9b34fb\" # Battery Level Characteristic UUID\n\nasync def discover_devices():\n    print(\"Scanning for 5 seconds...\")\n    devices = await BleakScanner.discover(timeout=5.0)\n    for d in devices:\n        print(f\"Device: {d.name} ({d.address})\")\n    print(\"\\nDiscovery complete.\")\n    return devices\n\nasync def connect_and_read(address: str):\n    try:\n        async with BleakClient(address) as client:\n            if not client.is_connected:\n                print(f\"Failed to connect to {address}\")\n                return\n            print(f\"Connected to {client.address}\")\n\n            # Read a characteristic (e.g., Battery Level)\n            try:\n                battery_level = await client.read_gatt_char(BATTERY_LEVEL_CHAR_UUID)\n                print(f\"Battery Level: {int.from_bytes(battery_level, 'little')}%\")\n            except Exception as e:\n                print(f\"Could not read battery level characteristic: {e}\")\n            \n            # List all services and characteristics (optional)\n            print(\"\\nServices and Characteristics:\")\n            for service in client.services:\n                print(f\"  Service: {service.uuid} ({service.description})\")\n                for char in service.characteristics:\n                    print(f\"    Characteristic: {char.uuid} ({char.description}) - Properties: {char.properties}\")\n                    for descriptor in char.descriptors:\n                        print(f\"      Descriptor: {descriptor.uuid}\")\n\n    except Exception as e:\n        print(f\"An error occurred: {e}\")\n\nasync def main():\n    # First, discover devices to find the address\n    # devices = await discover_devices()\n    # For direct connection, replace DEVICE_ADDRESS with your target's address\n    \n    await connect_and_read(DEVICE_ADDRESS)\n\nif __name__ == \"__main__\":\n    # Make sure not to name your script 'bleak.py' to avoid circular import errors.\n    asyncio.run(main())\n","lang":"python","description":"This quickstart demonstrates how to scan for nearby Bluetooth Low Energy devices using `BleakScanner` and then connect to a specific device using `BleakClient` to read a GATT characteristic, such as the battery level. It highlights the asynchronous nature of Bleak operations, requiring `asyncio` to run. Remember to replace placeholder UUIDs and addresses with those relevant to your device."},"warnings":[{"fix":"Catch `bleak.exc.BleakGATTProtocolError`. The `code` property of `BleakGATTProtocolError` can be used to get the actual underlying error code.","message":"OS-specific GATT exceptions (e.g., `BleakDBusError`) are now wrapped in `BleakGATTProtocolError` for cross-platform consistency. If you were catching these specific exceptions, you should now catch `BleakGATTProtocolError` or both for multi-version compatibility.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Use the new `bluez={'adapter': 'hci0'}` keyword argument instead. For compatibility, both can be passed, or the deprecation warning can be suppressed.","message":"The `adapter` keyword argument in `BleakScanner` and `BleakClient` has been deprecated. This affects how a specific Bluetooth adapter is selected.","severity":"deprecated","affected_versions":">=3.0.0"},{"fix":"Ensure your environment uses Python 3.10 or newer (as per PyPI `requires_python`), macOS 10.15 or newer, and BlueZ 5.55 or newer.","message":"Support for Python 3.8 and macOS versions older than 10.13, and BlueZ versions older than 5.55 has been removed.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Structure your code with a single asynchronous `main()` function that calls `asyncio.run(main())` only once at the program's entry point.","message":"Calling `asyncio.run()` multiple times in the same program can lead to crashes and incorrect behavior because Bleak requires all operations to use the same running asyncio event loop.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Rename your script to something else (e.g., `my_ble_app.py`, `scanner.py`).","message":"Naming your Python script `bleak.py` will cause an `ImportError` due to a circular import, as Python will try to import your script instead of the installed library.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Adjust your connection logic if you rely on a shorter timeout, or explicitly set the `timeout` parameter in the `BleakClient` constructor or `connect()` method.","message":"The default connection timeout for `BleakClient` has been increased from 10 seconds to 30 seconds. This might affect applications expecting a quicker timeout.","severity":"gotcha","affected_versions":">=2.1.1"},{"fix":"Adjust imports to use the correct `bleak.args` module directly for type hinting and argument handling.","message":"Importing `bleak.args.*` types from `bleak.backends.*` has been deprecated.","severity":"deprecated","affected_versions":">=1.0.1"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}