diff options
Diffstat (limited to 'client/python/service_explorer.py')
| -rw-r--r-- | client/python/service_explorer.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/client/python/service_explorer.py b/client/python/service_explorer.py new file mode 100644 index 0000000..5649bb5 --- /dev/null +++ b/client/python/service_explorer.py @@ -0,0 +1,126 @@ +""" +Service Explorer +---------------- + +An example showing how to access and print out the services, characteristics and +descriptors of a connected GATT server. + +Created on 2019-03-25 by hbldh <henrik.blidh@nedomkull.com> + +""" + +import argparse +import asyncio +import logging + +from bleak import BleakClient, BleakScanner + +logger = logging.getLogger(__name__) + + +async def main(args: argparse.Namespace): + logger.info("starting scan...") + + if args.address: + device = await BleakScanner.find_device_by_address( + args.address, cb=dict(use_bdaddr=args.macos_use_bdaddr) + ) + if device is None: + logger.error("could not find device with address '%s'", args.address) + return + else: + device = await BleakScanner.find_device_by_name( + args.name, cb=dict(use_bdaddr=args.macos_use_bdaddr) + ) + if device is None: + logger.error("could not find device with name '%s'", args.name) + return + + logger.info("connecting to device...") + + async with BleakClient( + device, + services=args.services, + ) as client: + logger.info("connected") + + for service in client.services: + logger.info("[Service] %s", service) + + for char in service.characteristics: + if "read" in char.properties: + try: + value = await client.read_gatt_char(char.uuid) + extra = f", Value: {value}" + except Exception as e: + extra = f", Error: {e}" + else: + extra = "" + + if "write-without-response" in char.properties: + extra += f", Max write w/o rsp size: {char.max_write_without_response_size}" + + logger.info( + " [Characteristic] %s (%s)%s", + char, + ",".join(char.properties), + extra, + ) + + for descriptor in char.descriptors: + try: + value = await client.read_gatt_descriptor(descriptor.handle) + logger.info(" [Descriptor] %s, Value: %r", descriptor, value) + except Exception as e: + logger.error(" [Descriptor] %s, Error: %s", descriptor, e) + + logger.info("disconnecting...") + + logger.info("disconnected") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + device_group = parser.add_mutually_exclusive_group(required=True) + + device_group.add_argument( + "--name", + metavar="<name>", + help="the name of the bluetooth device to connect to", + ) + device_group.add_argument( + "--address", + metavar="<address>", + help="the address of the bluetooth device to connect to", + ) + + parser.add_argument( + "--macos-use-bdaddr", + action="store_true", + help="when true use Bluetooth address instead of UUID on macOS", + ) + + parser.add_argument( + "--services", + nargs="+", + metavar="<uuid>", + help="if provided, only enumerate matching service(s)", + ) + + parser.add_argument( + "-d", + "--debug", + action="store_true", + help="sets the log level to debug", + ) + + args = parser.parse_args() + + log_level = logging.DEBUG if args.debug else logging.INFO + logging.basicConfig( + level=log_level, + format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s", + ) + + asyncio.run(main(args)) |
