Bluetooth Quickstart

Background

Lager provides a simplified API for the most common Bluetooth tasks. If you need more control over the Bluetooth stack or are familiar with async Python, see Bluetooth (Advanced)

Creating a BLE Central

A BLE central object can be used to scan and connect to devices

ble-central.py
 from lager.ble import Central
 central = Central()

Scanning

ble-scan.py
 from lager.ble import Central
 def main():
     central = Central()
     # `central.scan` takes two optional keyword args, `name` and `address`, which
     # will filter the list of results down to those devices which match. If neither
     # is provided, all scanned devices will be returned
     for device in central.scan(name='MyDevice'):
         print(device)
         print(device.metadata)

 if __name__ == '__main__':
     main()
➜  lager python ble-scan.py
F2:E6:41:55:6F:09: MyDevice
{'uuids': ['0000fe78-0000-1000-8000-00805f9b34fb'], 'manufacturer_data': {101: b'\x01\xc9\x05'}}

Connecting and listing services and characteristics

ble-connect.py
 from lager.ble import Central
 def main():
     central = Central()
     with central.connect('F2:E6:41:55:6F:09') as client:
         services = client.get_services()
         print(services['0000180a-0000-1000-8000-00805f9b34fb'] is None)
         print(services['a000180a-0000-1000-8000-00805f9b34fb'] is None)
         for service in client.get_services():
             print(service)
             for characteristic in service.characteristics:
                 print(f'\t{characteristic}')

 if __name__ == '__main__':
     main()
➜  lager python ble-connect.py
False
True
00001801-0000-1000-8000-00805f9b34fb (Handle: 10): Generic Attribute Profile
    00002a05-0000-1000-8000-00805f9b34fb (Handle: 11): Service Changed
0000180a-0000-1000-8000-00805f9b34fb (Handle: 14): Device Information
    00002a29-0000-1000-8000-00805f9b34fb (Handle: 15): Manufacturer Name String
    00002a26-0000-1000-8000-00805f9b34fb (Handle: 17): Firmware Revision String
    00002a23-0000-1000-8000-00805f9b34fb (Handle: 19): System ID
0000180f-0000-1000-8000-00805f9b34fb (Handle: 21): Battery Service
    00002a19-0000-1000-8000-00805f9b34fb (Handle: 22): Battery Level
8e7c6065-7656-17ad-1b41-b53d1a548e0d (Handle: 25): Unknown
    10c2be2d-d2d5-b7a8-5f42-e2468c9ebbf5 (Handle: 26): Unknown
    49e830a0-57dd-11e4-8ac4-0002a5d5c51b (Handle: 30): Unknown
    453ad6d2-c7f2-16ae-6948-1859e5f040d0 (Handle: 34): Unknown

Read GATT characteristic

ble-read.py
from lager.ble import Central
def main():
    central = Central()
    with central.connect('F2:E6:41:55:6F:09') as client:
        val = client.read_gatt_char('00002a19-0000-1000-8000-00805f9b34fb')
        print(val[0])

if __name__ == '__main__':
    main()
➜  lager python ble-read.py
88

Write GATT characteristic

ble-write.py
from lager.ble import Central
def main():
    central = Central()
    with central.connect('F2:E6:41:55:6F:09') as client:
        client.write_gatt_char('00002a19-0000-1000-8000-00805f9b34fb', b'Data')

if __name__ == '__main__':
    main()

Notify GATT characteristic

ble-notify.py
from lager.ble import Central
STREAMING_DATA_CHAR_UUID = "10c2be2d-d2d5-b7a8-5f42-e2468c9ebbf5"
def main():
    central = Central()
    with central.connect('F2:E6:41:55:6F:09') as client:
        try:
            # start_notify also takes an optional "callback" parameter that will be called as messages
            # arrive; e.g. `callback=notify_cb`. The callback takes two arguments, an integer handle
            # for the characteristic and a bytearray of the data received
            timed_out, messages = client.start_notify(STREAMING_DATA_CHAR_UUID, max_messages=5, timeout=5)
            print(f"Timed out: {timed_out}")
            print(messages)
        finally:
            client.stop_notify(STREAMING_DATA_CHAR_UUID)

def notify_cb(handle: int, data: bytearray):
    print(f"Received data: {data}")

if __name__ == '__main__':
    main()
➜  lager python ble-notify.py
Received data: bytearray(b'1')
Received data: bytearray(b'2')
Received data: bytearray(b'3')
Received data: bytearray(b'4')
Received data: bytearray(b'5')
Timed out: False
[bytearray(b'1'), bytearray(b'2'), bytearray(b'3'), bytearray(b'4'), bytearray(b'5')]