From 1762c56956bafd6fc0636516b494dfa935ff8aec Mon Sep 17 00:00:00 2001 From: Bernhard Guillon Date: Wed, 25 Dec 2024 00:34:42 +0100 Subject: space_light: first version TODO: pwm initialization is currently best guess could be wrong active low|high TODO: implement pairing TODO: implement timer TODO: use the button for something TODO: implement a better client --- client/python/client.py | 55 +++++++++++++++++ client/python/scan.py | 13 ++++ client/python/service_explorer.py | 126 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 client/python/client.py create mode 100644 client/python/scan.py create mode 100644 client/python/service_explorer.py (limited to 'client') diff --git a/client/python/client.py b/client/python/client.py new file mode 100644 index 0000000..4cd4672 --- /dev/null +++ b/client/python/client.py @@ -0,0 +1,55 @@ +""" +2024-12-22 23:07:22,916 __main__ INFO: starting scan... +2024-12-22 23:07:23,257 __main__ INFO: connecting to device... +2024-12-22 23:07:23,910 __main__ INFO: connected +2024-12-22 23:07:23,910 __main__ INFO: [Service] 00001801-0000-1000-8000-00805f9b34fb (Handle: 6): Generic Attribute Profile +2024-12-22 23:07:23,911 __main__ INFO: [Service] 00000000-0000-1000-8000-00805f9b34fb (Handle: 7): Vendor specific +2024-12-22 23:07:23,911 __main__ INFO: [Characteristic] 00000002-0000-1001-8001-00805f9b07d0 (Handle: 10): Unknown (notify) +2024-12-22 23:07:24,173 __main__ INFO: [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 12): Client Characteristic Configuration, Value: bytearray(b'\x00\x00') +2024-12-22 23:07:24,174 __main__ INFO: [Characteristic] 00000001-0000-1001-8001-00805f9b07d0 (Handle: 8): SDP (write-without-response,write), Max write w/o rsp size: 253 +2024-12-22 23:07:24,174 __main__ INFO: disconnecting... +2024-12-22 23:07:28,414 __main__ INFO: disconnected +""" + +import asyncio +import binascii +from bleak import BleakClient + +def callback(_: int, data: bytearray): + print("received:", data) + print("received:", data.hex()) + print("len:", len(data)) + +def convertInput(i): + decimal_value = int(i) + hex_string = hex(decimal_value).split('x')[-1] + if len(hex_string) % 2 != 0: + hex_string = '0' + hex_string + byte_array = binascii.unhexlify(hex_string) + return byte_array + +async def main(): + ble_address = "8D:FE:5B:68:D6:D9" + characteristic = "00000001-0000-1001-8001-00805f9b07d0" + notify_listen = "00000002-0000-1001-8001-00805f9b07d0" + + async with BleakClient(ble_address) as client: + #await client.write_gatt_char(characteristic, b"\x00\x01\xf4", response=False) + #await client.write_gatt_char(characteristic, b"\x01\x00\x00", response=False) + #await client.write_gatt_char(characteristic, b"\x02\x00\x00", response=False) + # we’ll do the read/write operations here + print("Connected to BLE device") + print(client.is_connected) + while True: + usduty = input("rgbcw") +# c = convertInput(1) +# duty = convertInput(rgbcw) +# cmd = c + rgbcw +# print("sending command ") +# print(cmd) + await client.write_gatt_char(characteristic, b"\x01\xFF\xFF\xFF\x10\xFF", response=False) + try: + await client.start_notify(notify_listen, callback) + except Exception as e: + return +asyncio.run(main()) diff --git a/client/python/scan.py b/client/python/scan.py new file mode 100644 index 0000000..b5e8531 --- /dev/null +++ b/client/python/scan.py @@ -0,0 +1,13 @@ +# Bluetooth LE scanner +# Prints the name and address of every nearby Bluetooth LE device + +import asyncio +from bleak import BleakScanner + +async def main(): + devices = await BleakScanner.discover() + + for device in devices: + print(device) + +asyncio.run(main()) 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 + +""" + +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="", + help="the name of the bluetooth device to connect to", + ) + device_group.add_argument( + "--address", + metavar="
", + 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="", + 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)) -- cgit v1.2.3