Bluetooth / 5 min read

Get data from BLE with Python Bleak

How to get data from BLE devices with Python Bleak

On this page

Suitable For

  • 有 Python 基本概念 或 程式語言基礎

Prerequisite

  • Software
    • Python 3.8 or above ( 2024/01/26: Bleak 0.21.1 only support Python 3.8 or above )
  • Hardware
    • BLE device
    • Computer with BLE support ( 支援 Bluetooth 4.0 以上的電腦 )

Code

本篇利用 Python 的 Bleak 套件來取得資料,並直接解析資料

Bleak 是 MIT 授權的開源套件,其相關的文件放在 Reference 1-3

本篇所有程式碼都放在 Github

  1. 安裝 Bleak

    Code
    pip install bleak
  2. import Bleak 並且掃描周遭裝置

    Code
    import asynciofrom bleak import BleakScanner, BleakClientasync def main():    # Scan for all available devices    devices = await BleakScanner.discover()    for device in devices:        print(device)asyncio.run(main())

    執行結果如下圖:

    Terminal output listing discovered Bluetooth device addresses with unavailable names

    會找到所有周遭的裝置,並且列出 裝置地址 與 裝置名稱,後續可以利用這兩個資訊來建立連線

  3. 透過指定 裝置地址 或 裝置名稱 來建立連線

    • 指定裝置名稱

      Code
      import asynciofrom bleak import BleakScannertarget_device_name = "YOUR_DEVICE_NAME"async def main():    # Scan for all available devices    devices = await BleakScanner.discover()    for device in devices:        if device.name == target_device_name:            print(f"Found target device: {device.name}, {device.address}")asyncio.run(main())
    • 指定裝置地址

      Code
      import asynciofrom bleak import BleakScannertarget_address = "YOUR_DEVICE_ADDRESS"async def main():    # Scan for all available devices    devices = await BleakScanner.discover()    for device in devices:        if device.address == target_address:            print(f"Found target device: {device.name}, {device.address}")asyncio.run(main())
  4. 建立連線後,表列出此裝置所支援的所有 Services 和 Characteristics

    Code
    import asynciofrom bleak import BleakScanner, BleakClienttarget_device_name = "YOUR_DEVICE_NAME"async def main():    # Scan for all available devices    devices = await BleakScanner.discover()    for device in devices:        if device.name == target_device_name:            print(f"Found target device: {device.name}, {device.address}")            # Connect to the target device            async with BleakClient(device) as client:                print(f"Connected: {client.is_connected}")                services = await client.get_services()                # Print all services and characteristics                for service in services:                    print(f"Service: {service.uuid}")                    for char in service.characteristics:                        print(f"\tCharacteristic: {char.uuid}")asyncio.run(main())

    執行結果如下圖:

    Terminal output listing Generic Access, Generic Attribute, and Device Information service UUIDs and characteristics

    上圖表示的是此裝置所支援的所有 Services 和 Characteristics,僅有列出 UUID,此 UUID 是上一篇文章中提到的 ATT 中的 Attribute Types,代表服務類型

    具體的服務類型需要參考 藍牙 或 裝置 規格書

    依照藍牙規格書可以對應出上圖中的服務類型:

    類型UUID名稱
    Service0x1800Generic Access service
    Characteristic0x2A00Device Name
    Characteristic0x2A01Appearance
    Characteristic0x2A04Peripheral Preferred Connection Parameters
    Service0x1801Generic Attribute service
    Service0x180ADevice Information service
    Characteristic0x2a23System ID
    Characteristic0x2a24Model Number String
    Characteristic0x2a25Serial Number String
    Characteristic0x2a26Firmware Revision String
    Characteristic0x2a27Hardware Revision String
    Characteristic0x2a28Software Revision String
    Characteristic0x2a29Manufacturer Name String
    Characteristic0x2a2aIEEE 11073-20601 Regulatory Certification Data List
    Characteristic0x2a50PnP ID
  5. 透過指定 Service 和 Characteristic 來取得資料

    Code
    import asynciofrom bleak import BleakScanner, BleakClienttarget_device_name = "YOUR_DEVICE_NAME"DEVICE_INFO_SERVICE_UUID = "0000180a-0000-1000-8000-00805f9b34fb"MANUFACTURER_NAME_CHAR_UUID = "00002a29-0000-1000-8000-00805f9b34fb"MODEL_NUMBER_CHAR_UUID = "00002a24-0000-1000-8000-00805f9b34fb"async def main():    # Scan for all available devices    devices = await BleakScanner.discover()    for device in devices:        if device.name == target_device_name:            print(f"Found target device: {device.name}, {device.address}")            async with BleakClient(device) as client:                print(f"Connected: {client.is_connected}")                services = await client.get_services()                print("Reading device information...")                for service in services:                    if service.uuid == DEVICE_INFO_SERVICE_UUID:                        print(f"Device Information Service: {service.uuid}")                        for char in service.characteristics:                            if char.uuid == MANUFACTURER_NAME_CHAR_UUID:                                manufacturer_name = await client.read_gatt_char(char)                                print(f"\tManufacturer Name: {manufacturer_name}")                            elif char.uuid == MODEL_NUMBER_CHAR_UUID:                                model_number = await client.read_gatt_char(char)                                print(f"\tModel Number: {model_number}")asyncio.run(main())

    執行結果如下圖:

    Terminal output showing the Bluetooth Device Information Service model number and manufacturer name values

    後續可以透過 client.read_gatt_char(char) 來取得資料,並且透過 client.write_gatt_char(char, data) 來寫入資料

Reference

  1. Bleak Github
  2. Bleak Pypi
  3. Bleak Official Document
  4. Sample Code Github Repository

Discussion

留言會在接近此區域時載入。