From c6c4134d4a0eb0ed52074a19f094787ee1959493 Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Tue, 7 Jun 2022 16:55:10 -0600 Subject: [PATCH] esp_prov: make service_name optional for BLE and allow interactive scanning and selection of device --- tools/esp_prov/esp_prov.py | 2 - tools/esp_prov/transport/ble_cli.py | 66 ++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/tools/esp_prov/esp_prov.py b/tools/esp_prov/esp_prov.py index 8e5333e39f6..49419407cdd 100644 --- a/tools/esp_prov/esp_prov.py +++ b/tools/esp_prov/esp_prov.py @@ -57,8 +57,6 @@ async def get_transport(sel_transport, service_name): service_name = '192.168.4.1:80' tp = transport.Transport_HTTP(service_name) elif (sel_transport == 'ble'): - if service_name is None: - raise RuntimeError('"--service_name" must be specified for ble transport') # BLE client is now capable of automatically figuring out # the primary service from the advertisement data and the # characteristics corresponding to each endpoint. diff --git a/tools/esp_prov/transport/ble_cli.py b/tools/esp_prov/transport/ble_cli.py index f7d626bc3fc..ed3946ea510 100644 --- a/tools/esp_prov/transport/ble_cli.py +++ b/tools/esp_prov/transport/ble_cli.py @@ -23,6 +23,10 @@ # -------------------------------------------------------------------- +def device_sort(device): + return device.address + + class BLE_Bleak_Client: def __init__(self): self.adapter_props = None @@ -46,23 +50,56 @@ async def connect(self, devname, iface, chrc_names, fallback_srv_uuid): raise RuntimeError('Bluetooth is not ready. Maybe try `bluetoothctl power on`?') raise - address = None - for d in devices: - if d.name == self.devname: - address = d.address - uuids = d.metadata['uuids'] - # There should be 1 service UUID in advertising data - # If bluez had cached an old version of the advertisement data - # the list of uuids may be incorrect, in which case connection - # or service discovery may fail the first time. If that happens - # the cache will be refreshed before next retry - if len(uuids) == 1: - self.srv_uuid_adv = uuids[0] - if not address: + found_device = None + + if self.devname is None: + if len(devices) == 0: + print('No devices found!') + exit(1) + + while True: + devices.sort(key=device_sort) + print('==== BLE Discovery results ====') + print('{0: >4} {1: <33} {2: <12}'.format( + 'S.N.', 'Name', 'Address')) + for i in range(len(devices)): + print('[{0: >2}] {1: <33} {2: <12}'.format(i + 1, devices[i].name, devices[i].address)) + + while True: + try: + select = int(input('Select device by number (0 to rescan) : ')) + if select < 0 or select > len(devices): + raise ValueError + break + except ValueError: + print('Invalid input! Retry') + + if select != 0: + break + + devices = await bleak.discover() + + self.devname = devices[select - 1].name + found_device = devices[select - 1] + else: + for d in devices: + if d.name == self.devname: + found_device = d + + if not found_device: raise RuntimeError('Device not found') + uuids = found_device.metadata['uuids'] + # There should be 1 service UUID in advertising data + # If bluez had cached an old version of the advertisement data + # the list of uuids may be incorrect, in which case connection + # or service discovery may fail the first time. If that happens + # the cache will be refreshed before next retry + if len(uuids) == 1: + self.srv_uuid_adv = uuids[0] + print('Connecting...') - self.device = bleak.BleakClient(address) + self.device = bleak.BleakClient(found_device.address) await self.device.connect() # must be paired on Windows to access characteristics; # cannot be paired on Mac @@ -123,7 +160,6 @@ async def send_data(self, characteristic_uuid, data): await self.device.write_gatt_char(characteristic_uuid, bytearray(data.encode('latin-1')), True) readval = await self.device.read_gatt_char(characteristic_uuid) return ''.join(chr(b) for b in readval) - # --------------------------------------------------------------------