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 :ref:`bluetooth-advanced` Creating a BLE Central ---------------------- A BLE central object can be used to scan and connect to devices .. code-block:: python :caption: ble-central.py :name: BLE central from lager.ble import Central central = Central() Scanning -------- .. code-block:: python :caption: ble-scan.py :name: Simple BLE scan 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() .. code-block:: console ➜ 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 --------------------------------------------------- .. code-block:: python :caption: ble-connect.py :name: Simple BLE connect 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() .. code-block:: console ➜ 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 ------------------------ .. code-block:: python :caption: ble-read.py :name: Simple BLE read 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() .. code-block:: console ➜ lager python ble-read.py 88 Write GATT characteristic ------------------------- .. code-block:: python :caption: ble-write.py :name: Simple BLE write 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 -------------------------- .. code-block:: python :caption: ble-notify.py :name: Simple BLE notify 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() .. code-block:: console ➜ 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')]