aboutsummaryrefslogtreecommitdiffstats
path: root/client/python/service_explorer.py
diff options
context:
space:
mode:
Diffstat (limited to 'client/python/service_explorer.py')
-rw-r--r--client/python/service_explorer.py126
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))