Bleak: Bluetooth Low Energy Client
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.
Warnings
- breaking 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.
- deprecated The `adapter` keyword argument in `BleakScanner` and `BleakClient` has been deprecated. This affects how a specific Bluetooth adapter is selected.
- breaking Support for Python 3.8 and macOS versions older than 10.13, and BlueZ versions older than 5.55 has been removed.
- gotcha 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.
- gotcha 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.
- gotcha The default connection timeout for `BleakClient` has been increased from 10 seconds to 30 seconds. This might affect applications expecting a quicker timeout.
- deprecated Importing `bleak.args.*` types from `bleak.backends.*` has been deprecated.
Install
-
pip install bleak
Imports
- BleakScanner
from bleak import BleakScanner
- BleakClient
from bleak import BleakClient
- BleakError
from bleak.exc import BleakError
- BleakGATTProtocolError
from bleak.exc import BleakGATTProtocolError
- BleakDBusError
from bleak.exc import BleakDBusError
Quickstart
import asyncio
from bleak import BleakScanner, BleakClient
# Replace with the actual address of your BLE device
# For macOS, this might be a UUID. For Linux/Windows, a MAC address.
# You can find the address by running the discovery part first.
DEVICE_ADDRESS = "XX:XX:XX:XX:XX:XX" # Example for a generic device
SERVICE_UUID = "0000180f-0000-1000-8000-00805f9b34fb" # Battery Service UUID
BATTERY_LEVEL_CHAR_UUID = "00002a19-0000-1000-8000-00805f9b34fb" # Battery Level Characteristic UUID
async def discover_devices():
print("Scanning for 5 seconds...")
devices = await BleakScanner.discover(timeout=5.0)
for d in devices:
print(f"Device: {d.name} ({d.address})")
print("\nDiscovery complete.")
return devices
async def connect_and_read(address: str):
try:
async with BleakClient(address) as client:
if not client.is_connected:
print(f"Failed to connect to {address}")
return
print(f"Connected to {client.address}")
# Read a characteristic (e.g., Battery Level)
try:
battery_level = await client.read_gatt_char(BATTERY_LEVEL_CHAR_UUID)
print(f"Battery Level: {int.from_bytes(battery_level, 'little')}%")
except Exception as e:
print(f"Could not read battery level characteristic: {e}")
# List all services and characteristics (optional)
print("\nServices and Characteristics:")
for service in client.services:
print(f" Service: {service.uuid} ({service.description})")
for char in service.characteristics:
print(f" Characteristic: {char.uuid} ({char.description}) - Properties: {char.properties}")
for descriptor in char.descriptors:
print(f" Descriptor: {descriptor.uuid}")
except Exception as e:
print(f"An error occurred: {e}")
async def main():
# First, discover devices to find the address
# devices = await discover_devices()
# For direct connection, replace DEVICE_ADDRESS with your target's address
await connect_and_read(DEVICE_ADDRESS)
if __name__ == "__main__":
# Make sure not to name your script 'bleak.py' to avoid circular import errors.
asyncio.run(main())