Example #1
0
    async def connect(self, hub):
        self.message(f'Starting scan for UART {hub.uart_uuid}')

        # HACK
        try:
            ble_id = uuid.UUID(hub.ble_id) if hub.ble_id else None
        except ValueError:
            # In case the user passed in a
            self.message_info(f"ble_id {hub.ble_id} is not a parseable UUID, so assuming it's a BLE network addresss")
            ble_id = hub.ble_id

        await self._ble_connect(hub.uart_uuid, hub.ble_name, hub.manufacturer_id, ble_id)

        self.message(f"found device {self.device.name}")


        device = bleak.BleakClient(address=self.device.address)
        self.devices.append(device)
        await device.connect()

        hub.ble_id = self.device.address
        self.message_info(f'Device advertised: {device.services.characteristics}')
        hub.tx = (device, hub.char_uuid)
        # Hack to fix device name on Windows
        if self.device.name == "Unknown" and hasattr(device._requester, 'Name'):
            self.device.name = device._requester.Name

        self.message_info(f"Connected to device {self.device.name}:{hub.ble_id}")
        self.hubs[hub.ble_id] = hub

        await self.get_messages(hub)
Example #2
0
    async def connect(self, address, timeout=1):
        '''
		Connects to device with given MAC address.
		The 'timeout' parameter specifices maximum time before giving up.
		'''
        if not address:
            raise ValueError(
                'Address is required. Please provide MAC address of target device'
            )
        time_start = time.time()

        # Using Bleak as backend
        client = bleak.BleakClient(address)
        connected = False
        err = None
        attempt_num = 0

        self.logger.info('connecting to device %s', address)

        while not connected and err is None:
            # Reattempts until timeout
            attempt_num = attempt_num + 1
            self.logger.debug(
                'attempting connection to device with address %s', address)
            try:
                await client.connect()
                connected = True
            except Exception as e:
                self.logger.debug("connection attempt #%d failed: %s",
                                  attempt_num, e)
                if time.time() - time_start < timeout:
                    # Sleep 250ms between attempts
                    await asyncio.sleep(0.25)
                else:
                    err = e
                    self.logger.warning('connection attempt timed out')

        if not connected:
            # Raise last exception when giving up
            raise err if err is not None else ValueError(
                'connection failed in an unexpected way')

        self.logger.info('succesfully connected to device %s', address)
        self.connected = True
        self.bleak_client = client
        self.connected_address = address
        self.wrote_security_access = False

        # Profiles
        self.logger.debug('profiling the device')
        try:
            await self._profile_device()
        except Exception as e:
            self.logger.exception('error profiling device: %s', e)

        # Pings (reading a DeviceInfo register) to verify communication
        self.logger.debug('verifying communication layer')
        await self.ping()

        return self.bleak_client
Example #3
0
    async def asyncio_loop(self):

        # Wait for messages on in_queue
        done = False
        while not done:
            msg = await self.in_queue.get()
            if isinstance(msg, tuple):
                msg, val = msg
            await self.in_queue.task_done()
            if msg == 'discover':
                print('Awaiting on bleak discover')
                devices = await bleak.discover(timeout=1, loop=self.loop)
                print('Done Awaiting on bleak discover')
                await self.out_queue.put(devices)
            elif msg == 'connect':
                device = bleak.BleakClient(address=val, loop=self.loop)
                self.devices.append(device)
                await device.connect()
                await self.out_queue.put(device)
            elif msg == 'tx':
                device, char_uuid, msg_bytes = val
                await device.write_gatt_char(char_uuid, msg_bytes)
            elif msg == 'notify':
                device, char_uuid, msg_handler = val
                await device.start_notify(char_uuid, msg_handler)
            elif msg == 'quit':
                print("quitting")
                logging.info('quitting')
                for device in self.devices:
                    await device.disconnect()
                done = True
                print("quit")
            else:
                print(f'Unknown message to Bleak: {msg}')
Example #4
0
async def get_device_services(device):
    try:
        async with bleak.BleakClient(device.address) as server:
            services = await server.get_services()
    except bleak.exc.BleakError:
        services = None
    return device, services
Example #5
0
    async def example(self):
        while self.running:
            try:
                self.line("scanning")
                scanned_devices = await bleak.BleakScanner.discover(1)
                self.line("scanned", True)

                if len(scanned_devices) == 0:
                    raise bleak.exc.BleakError("no devices found")

                scanned_devices.sort(key=lambda device: -device.rssi)

                for device in scanned_devices:
                    self.line(f"{device.name} {device.rssi}dB")

                for device in scanned_devices:
                    self.line(f"Connecting to {device.name} ...")
                    try:
                        async with bleak.BleakClient(device) as client:
                            services = await client.get_services()
                            for service in services.services.values():
                                self.line(f"  service {service.uuid}")
                                for characteristic in service.characteristics:
                                    self.line(
                                        f"  characteristic {characteristic.uuid} {hex(characteristic.handle)} ({len(characteristic.descriptors)} descriptors)"
                                    )
                    except bleak.exc.BleakError as e:
                        self.line(f"  error {e}")
                        asyncio.sleep(10)
            except bleak.exc.BleakError as e:
                self.line(f"ERROR {e}")
                await asyncio.sleep(1)
        self.line("example loop terminated", True)
Example #6
0
async def run(addr, host):
    async with asyncio_mqtt.Client(host) as mqtt:
        async with bleak.BleakClient(addr) as dev:
            svcs = await dev.get_services()
            for char in svcs.characteristics.values():
                if char.uuid.startswith('0000ffe1'):
                    light_char = char
                    break
            else:
                print('not found')
                return

            print(light_char)

            topic = 'led/{}/rgb'.format(addr)
            print(topic)
            async with mqtt.filtered_messages(topic) as msgs:
                await mqtt.subscribe(topic)
                async for msg in msgs:
                    rgb_str = msg.payload.decode()
                    print(rgb_str)
                    parts = [int(n) for n in rgb_str.split()]
                    for val in parts:
                        assert 0 <= val <= 255
                    r, g, b = parts
                    data = bytearray([r, g, b, 0x1e])
                    await dev.write_gatt_char(light_char, data)
Example #7
0
async def open_bluetooth_cli(device_name='Project21',
                             rx_uuid='6e400002-b5a3-f393-e0a9-e50e24dcca9e',
                             tx_uuid='6e400003-b5a3-f393-e0a9-e50e24dcca9e',
                             *,
                             log=print):
    """opens cli with bluetooth device as async coroutine
    first iteration will connect to the device and yield initial prompt from device
    subsequently should call .asend(message) to send the message to the device
    this will read the output and produce it as a response to the asend call.
    """
    device = await scan_for_device(device_name, log=log)
    is_connected = True

    def device_has_disconnected(c=None):
        nonlocal is_connected
        log("BLUETOOTH DEVICE DISCONNECTED")
        is_connected = False

    log("BEFORE WITH")
    async with bleak.BleakClient(device.address) as client:
        log("INSIDE WITH")
        client.set_disconnected_callback(device_has_disconnected)
        # TODO: check this makes sense once I can actually test it.
        while is_connected:
            output_from_device = await client.read_gatt_char(rx_uuid)
            msg_send_to_device = yield output_from_device
            await client.write_gatt_char(tx_uuid, msg_send_to_device.encode())
    log("closed connection with bluetooth device")
Example #8
0
async def read_data(address, done, handler):
    async with bleak.BleakClient(address) as client:
        x = await client.is_connected()
        print("Connected: {0}".format(x))

        notification_handler = make_handler(handler)
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
        await done.wait()
        print('Disconnecting ...')
Example #9
0
 async def device(self, address):
     try:
         client = bleak.BleakClient(address)
         await client.connect()
         device = LEDevice(self, address, client)
         self._connected.append(device)
         return device
     except Exception as e:
         print('== failed to connect to {} =='.format(address), e)
         return None
Example #10
0
async def connect(loop, address, uuid):
    async with bleak.BleakClient(address, loop=loop,
                                 timeout=args.timeout) as client:
        message = await client.read_gatt_char(uuid, timeout=args.timeout)
        now = datetime.datetime.now().isoformat()
        if args.json:  #soooo deeeeep . what is pep8?
            data = {"time": now, "data": message.decode(), "address": address}
            print(json.dumps(data))
        else:
            print(f'[{now}] {address} : {message.decode()}')
Example #11
0
    def __init__(self,
                 address,
                 name=None,
                 *args,
                 default_timeout=DEFAULT_TIMEOUT):
        import bleak

        self._address = address
        self._name = name
        self._client = bleak.BleakClient(self._address)
        self._default_timeout = DEFAULT_TIMEOUT
Example #12
0
 def __init__(self, address):
     self.__event_loop = asyncio.new_event_loop()
     self.__device = bleak.BleakClient(address, loop=self.__event_loop, timeout=5.0)
     self.__lock = threading.Lock()
     self.__thread = threading.Thread(target=self.__event_loop.run_forever)
     self.__thread.start()
     try:
         self.__execute(self.__device.connect())
     except:
         self.close(False)
         raise
Example #13
0
    def __init__(self,
                 address,
                 name=None,
                 *args,
                 default_timeout=DEFAULT_TIMEOUT):
        import bleak

        self._address = address
        self._name = name
        self._client = bleak.BleakClient(self._address)
        self._notification_queue = asyncio.Queue(maxsize=1)
        self._default_timeout = DEFAULT_TIMEOUT
Example #14
0
    async def connect(self, timeout=2, retries=None) -> bool:
        """Connect to the specified GATT server.

		Returns:
			Boolean representing connection status.

		"""
        if self.client is not None:
            try:
                if await asyncio.wait_for(self.is_connected(), self.timeout):
                    self.logger.debug("Devices is already connected.")
                    return True
            except Exception as e:
                self.logger.error(
                    f"[BleClient.{currentFuncName()}] received exception: " +
                    str(e))

        if retries is None:
            retries = self.maxretries

        for i in range(0, retries):
            try:
                self.client = bleak.BleakClient(self.address, self.loop)

                # Overrides the bleak connect method #
                self.client.connect = types.MethodType(
                    new_bleak_client_connect.connect, self.client)

                t1 = time.perf_counter()
                status = await asyncio.wait_for(
                    self.client.connect(timeout=timeout), self.timeout)
                t2 = time.perf_counter() - t1
                self.logger.info(
                    f"[BleClient.{currentFuncName()}] connection established in {round(t2,2)}s in {i+1} of {retries} tries."
                )
                return status

            except Exception as e:
                del self.client
                self.client = None

                if (i + 1) < retries:
                    self.logger.warning(
                        f"[BleClient.{currentFuncName()}] failed to connect in {str(i+1)} of {str(retries)} tries."
                        + " Received exception: " + str(e))
                else:
                    self.logger.error(
                        f"[BleClient.{currentFuncName()}] could not connect to device."
                        + " Received exception: " + str(e))
                    raise e
Example #15
0
    def __init__(self,
                 *args: object,
                 adapter: Optional[str] = None,
                 **kwargs: object):
        """
        Initialization of an instance of a remote RadonEye RD200
        :param address_or_ble_device: The Bluetooth address of the BLE
        peripheral to connect to or the `BLEDevice` object representing it.
        """

        # Can't pass adapter=None to BleakClient
        if adapter is not None:
            kwargs.update(adapter=adapter)

        self.device = bleak.BleakClient(*args, **kwargs)

        self._ctl: Optional[BleakGATTCharacteristic] = None
        self._meas: Optional[BleakGATTCharacteristic] = None
        self._log: Optional[BleakGATTCharacteristic] = None
Example #16
0
 def __init__(
     self,
     target: Union[str, PranaDeviceInfo],
     loop: Optional[AbstractEventLoop] = None,
     iface: str = "hci0",
 ) -> None:
     self.__address = None
     if isinstance(target, PranaDeviceInfo):
         self.__address = target.address
     elif isinstance(target, str):
         self.__address = target
     else:
         raise ValueError(
             "PranaDevice constructor error: Target must be either mac address or PranaDeviceInfo instance"
         )
     self.__client = bleak.BleakClient(self.__address, device=iface)
     self.__has_connect_attempts = False
     self.__notification_bytes: Optional[bytearray] = None
     self.__state: Optional[PranaState] = None
     self.__read_state_event: Optional[asyncio.Event] = None
     self.__lock = Lock()
     self.__logger = logging.getLogger(self.__class__.__name__)
    async def run_session(self):
        """
        Connecting to the device that is associated with the given MAC address, configuring the resistance level of the
        workout, starting the workout session and reading data from the bike every second until it is finished.
        """
        try:
            loop = asyncio.get_event_loop()
            async with bleak.BleakClient(self.address, loop=loop) as self.client:
                await self.initialize_session()
                time.sleep(1)

                await self.set_level(self.workout_session.program.level)
                time.sleep(1)

                # Starting the workout session.
                await self.client.write_gatt_char(self.characteristic_uuid, START)
                time.sleep(1)

                while not self.stop_flag:
                    # Stopping the session if the session is out of time.
                    if self.current_minute == self.workout_session.program.duration:
                        break

                    # Reading the current data from the exercise bike.
                    await self.client.write_gatt_char(self.characteristic_uuid, READ)

                    # Changing the resistance level if the chosen workout program specifies it.
                    if self.current_minute < self.workout_session.program.duration:
                        new_level = self.workout_session.program.levels[self.current_minute]
                        if self.current_level != new_level:
                            await self.set_level(new_level)
                            self.current_level = new_level

                    time.sleep(1)

                await self.stop_session()
        except bleak.BleakError as e:
            print(f"Bleak raised an exception: {e}")
            await self.run_session()
    async def get_writeable_uuid(self, address, loop):
        """
        Looping through the characteristics of the given device and saving the uuid if a writeable characteristic
        is found. In this context "writeable" is defined as returning the correct notification when a READ packet is
        written to the characteristic, meaning that the given device is a viable exercise bike.

        :param address: The MAC address of the BLE device that should be checked for writeable characteristics.
        :param loop: The event loop used to connect to the device.
        """
        try:
            async with bleak.BleakClient(address, loop=loop) as client:
                services = await client.get_services()
                for key, value in services.characteristics.items():
                    try:
                        await client.start_notify(value.uuid,
                                                  self.notification_handler)
                        time.sleep(0.5)
                        await client.write_gatt_char(value.uuid, READ)
                    except bleak.BleakError as e:
                        print(f"Bleak raised an exception: {e}")
        except bleak.BleakError as e:
            print(f"Bleak raised an exception: {e}")
            await self.get_writeable_uuid(address, loop)
Example #19
0
def AV_ble_client(address_p="3C:71:BF:FD:31:EA"):
    return bleak.BleakClient(address_p)
Example #20
0
    async def connect_to_device(self, loop):
        print("starting", self.smartrowdevice.address, "loop")
        async with bleak.BleakClient(self.smartrowdevice.address,
                                     timeout=5.0) as client:

            print("connect to", self.smartrowdevice.address)
Example #21
0
def get_client(device):
    return bleak.BleakClient(device)
Example #22
0
async def run_all_devices(debug=False):

    if debug:
        import sys

        # loop.set_debug(True)
        l = logging.getLogger("asyncio")
        l.setLevel(logging.DEBUG)
        h = logging.StreamHandler(sys.stdout)
        h.setLevel(logging.DEBUG)
        l.addHandler(h)
        logger.addHandler(h)

    x = await bleak.BleakScanner.discover()
    l.info("*********** Start of discovered list *************")
    i = 1
    for d in x:
        #l.info(d)
        #l.info(bleak.utils.mac_str_2_int(d.address))
        print("[{0}]   ".format(i) + d.address + "  " + d.name)
        i += 1
        if i >= 10:
            break
        #if d.address == TARGET_ADDRESS:
        #    await found_unit(d)
    l.info("*********** End of discovered list ***************")

    print("Enter number to connect (or anything else to cancel):")

    s = input()

    try:
        j_s = int(s)
    except ValueError:
        j_s = -1

    if j_s > 0 and j_s <= len(x):
        # a good value!
        async with bleak.BleakClient(x[j_s - 1].address) as client:
            y = await client.is_connected()
            l.info("Connected: {0}".format(y))
            w = await client.get_services()
            w_serv = w.get_service(CONFIG_SERVICE_UUID.lower())
            l.info(w_serv)
            w_char = [
                w.get_characteristic(CONFIG_1_CHAR_UUID.lower()),
                w.get_characteristic(CONFIG_2_CHAR_UUID.lower()),
                w.get_characteristic(CONFIG_3_CHAR_UUID.lower())
            ]
            l.info(w_char[0].service_uuid)
            l.info(w_char[0])
            l.info(w_char[1].service_uuid)
            l.info(w_char[1])
            l.info(w_char[2].service_uuid)
            l.info(w_char[2])

            t_0 = await client.read_gatt_char(w_char[0])
            t_1 = await client.read_gatt_char(w_char[1])
            t_2 = await client.read_gatt_char(w_char[2])

            print(t_0)
            print(t_1)
            print(t_2)

            is_central = False

            if len(t_0) >= 1:
                is_central = ((t_0[0] & 0x01) != 0)
                if is_central:
                    print("This is a central device. Choose:")
                    print("[1] change to peripheral")
                    print("[2] no change (remain as central)")

                    s = input()

                    try:
                        k_s = int(s)
                    except ValueError:
                        k_s = 2

                    if k_s == 1:
                        await client.write_gatt_char(w_char[0],
                                                     bytearray(b'\x00'))
                        is_central = False
                        print("Changed")
                else:
                    print("This is a peripheral device. Choose:")
                    print("[1] no change (remain as peripheral)")
                    print("[2] change to central")

                    s = input()

                    try:
                        k_s = int(s)
                    except ValueError:
                        k_s = 1

                    if k_s == 2:
                        await client.write_gatt_char(w_char[0],
                                                     bytearray(b'\x01'))
                        print("Changed")
                        is_central = True

            if len(t_1) >= 4 and is_central:
                val_2 = struct.unpack('<I', t_1)[0]
                print("This is a central device with trigger threshold {0}.".
                      format(0x3FFF & val_2))
                print("Enter a new value, or <Enter> to keep old one:")

                s = input()

                try:
                    k_s = int(s)
                except ValueError:
                    k_s = -1

                if k_s >= 0:
                    new_val = (val_2 & 0xFFFFC000) | (k_s & 0x3FFF)
                    await client.write_gatt_char(
                        w_char[1], bytearray(struct.pack('<I', new_val)))
                    print("Changed")
                else:
                    print("No change")

            z = await client.disconnect()
            logger.info("Disconnected: {0}".format(z))
            await asyncio.sleep(1.0)

    await asyncio.sleep(1.0)
Example #23
0
async def run_specific_device_leaf(addr, debug=False):

    global rxed_data
    global rxed_data_2
    global dev_list
    global do_dev_list
    global is_leaf_locked
    global trigger_size

    if debug:
        import sys

        # loop.set_debug(True)
        l = logging.getLogger("asyncio")
        l.setLevel(logging.DEBUG)
        h = logging.StreamHandler(sys.stdout)
        h.setLevel(logging.DEBUG)
        l.addHandler(h)
        logger.addHandler(h)

    # Do an initial connection to wake it up
    #async with bleak.BleakClient(addr) as client:
    #    x = await client.is_connected()
    #    l.info("Connected: {0}".format(x))

    #await asyncio.sleep(40.0)

    # Now do the connection where we lock and read data
    async with bleak.BleakClient(addr) as client:
        x = await client.is_connected()
        l.info("Connected: {0}".format(x))
        y = await client.get_services()
        y_serv = y.get_service(SERVICE_UUID.lower())
        l.info(y_serv)
        y_char = y.get_characteristic(READ_CHAR_UUID.lower())
        l.info(y_char)
        l.info(y_char.service_uuid)

        await client.start_notify(READ_CHAR_UUID, notification_handler_leaf)

        if False:
            #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__IDENTIFY_SELF, 0)))  # no data, just send 0
            #await asyncio.sleep(2.0)

            await client.write_gatt_char(
                WRITE_CHAR_UUID,
                bytearray(
                    struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED,
                                0)))  # no data, just send 0
            await asyncio.sleep(0.2)

        else:

            #  #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0xe,0,0,0,0xff,0xff,0xff,0xff]))
            await client.write_gatt_char(
                WRITE_CHAR_UUID,
                bytearray(
                    struct.pack('<2I', INSTRUCTION_CODE__QUERY_IS_SYNCED,
                                0)))  # no data, just send 0
            await asyncio.sleep(0.2)
            await client.write_gatt_char(
                WRITE_CHAR_UUID,
                bytearray(
                    struct.pack('<2I', INSTRUCTION_CODE__QUERY_CURRENT_TIME,
                                0)))  # no data, just send 0
            await asyncio.sleep(0.2)
            await client.write_gatt_char(
                WRITE_CHAR_UUID,
                bytearray(struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED,
                                      0)))  # no data, just send 0
            await asyncio.sleep(0.2)

            #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__LOCK, 0xFFFFFFFF)))  # 0xFFFFFFFF means current time
            #await asyncio.sleep(0.4)
            await client.write_gatt_char(
                WRITE_CHAR_UUID,
                bytearray(struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED,
                                      0)))  # no data, just send 0
            await asyncio.sleep(
                5.)  # Need to give sufficient time for the buffer to fill up.
            # If not sufficient, nothing will be returned

            rxed_data = b''

            #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray(struct.pack('<2I', INSTRUCTION_CODE__READ_OUT, 0)))  # no data, just send 0
            #await asyncio.sleep(0.2)

        a = 0
        kk = 0
        while a < 1000:
            await asyncio.sleep(1.0)

            if do_dev_list:
                do_dev_list = False
                for dd in dev_list:
                    async with bleak.BleakClient(dd) as client_2:
                        x_2 = await client.is_connected()
                        l.info("Connected: {0}".format(x_2))
                        await client_2.start_notify(
                            READ_CHAR_UUID, notification_handler_leaf_2)
                        await asyncio.sleep(1.2)
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack('<2I',
                                            INSTRUCTION_CODE__QUERY_IS_SYNCED,
                                            0)))  # no data, just send 0
                        await asyncio.sleep(0.2)
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack(
                                    '<2I',
                                    INSTRUCTION_CODE__QUERY_CURRENT_TIME,
                                    0)))  # no data, just send 0
                        await asyncio.sleep(0.2)
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED,
                                            0)))  # no data, just send 0
                        await asyncio.sleep(0.4)

                        await client_2.stop_notify(READ_CHAR_UUID)

                        z_2 = await client_2.disconnect()
                        l.info("Disconnected: {0}".format(z_2))
            if trigger_size > 0:
                with open("Trigger_list.txt", "a") as f3:
                    f3.write(datetime.datetime.now().strftime(
                        "%Y/%m/%d %H:%M:%S  ") +
                             "{0}   {1}\n".format(trigger_size, len(dev_list)))
                trigger_size = 0
                for dd in dev_list:
                    async with bleak.BleakClient(dd) as client_2:
                        x_2 = await client.is_connected()
                        l.info("Connected: {0}".format(x_2))
                        await client_2.start_notify(
                            READ_CHAR_UUID, notification_handler_leaf_2)
                        await asyncio.sleep(1.2)
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack('<2I',
                                            INSTRUCTION_CODE__QUERY_IS_SYNCED,
                                            0)))  # no data, just send 0
                        await asyncio.sleep(0.2)
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack(
                                    '<2I',
                                    INSTRUCTION_CODE__QUERY_CURRENT_TIME,
                                    0)))  # no data, just send 0
                        await asyncio.sleep(0.2)
                        is_leaf_locked = False
                        await client_2.write_gatt_char(
                            WRITE_CHAR_UUID,
                            bytearray(
                                struct.pack('<2I', INSTRUCTION_CODE__IS_LOCKED,
                                            0)))  # no data, just send 0
                        await asyncio.sleep(0.4)
                        if is_leaf_locked:
                            rxed_data_2 = b''
                            await client_2.write_gatt_char(
                                WRITE_CHAR_UUID,
                                bytearray(
                                    struct.pack('<2I',
                                                INSTRUCTION_CODE__READ_OUT,
                                                0)))  # no data, just send 0
                            await asyncio.sleep(5.2)
                            if len(rxed_data_2) > 0:
                                with open(
                                        datetime.datetime.now().strftime(
                                            "%Y%m%d_%H%M%S_") +
                                        "{0:03d}_".format(kk) + dd + ".bin",
                                        "wb") as f1:
                                    f1.write(rxed_data_2)

                        await client_2.stop_notify(READ_CHAR_UUID)

                        z_2 = await client_2.disconnect()
                        l.info("Disconnected: {0}".format(z_2))
                kk += 1
            a += 1

        # Now save any data that has been received
        if len(rxed_data) > 0:
            with open(datetime.datetime.now().strftime("%Y%m%d_%H%M%S.bin"),
                      "wb") as f1:
                f1.write(rxed_data)
            with open(datetime.datetime.now().strftime("%Y%m%d_%H%M%S.txt"),
                      "w") as f1:
                i = 0
                j = 0
                while i + 8 <= len(rxed_data):
                    tt = struct.unpack('<4h', rxed_data[i:i + 8])

                    f1.write("{0},{1},{2},{3},{4}\n".format(
                        j, tt[0], tt[1], tt[2], tt[3]))
                    i += 8
                    j += 1

        rxed_data = b''
        await client.stop_notify(READ_CHAR_UUID)

        z = await client.disconnect()
        logger.info("Disconnected: {0}".format(z))
        await asyncio.sleep(1.0)
Example #24
0
 async def found_unit(dev):
     await asyncio.sleep(1.0)
     async with bleak.BleakClient(dev.address) as client:
         svcs = await client.get_services()
         print("Services:", svcs.services)
Example #25
0
 def __new_client(self) -> bleak.BleakClient:
     return bleak.BleakClient(self.__address, device=self.__iface)
Example #26
0
async def main():
    print("Connecting to", DEVICE_MAC, file=sys.stderr)
    async with bleak.BleakClient(DEVICE_MAC) as client:
        tasks = [asyncio.ensure_future(run(client))]
        await asyncio.gather(*tasks)
Example #27
0
    async def _connect_impl(self):
        assert self.client is None

        # Input received, buffered awaiting external read
        inbufs = collections.deque()

        # Async stream of those items for reading
        async def _input_stream():
            # Poll for new input all the time client exists
            while self.client is not None:
                while inbufs:
                    buf = inbufs.popleft()
                    for b in buf:
                        yield b

                # No data, yield to event loop awaiting arrival of more data
                await asyncio.sleep(0.01)

            # Stream drained and client connection no longer exists
            self.inputstream = None

        self.inputstream = _input_stream()

        # Scan for expected ble device
        # Match device-name only if no serial number provided
        device_mac = None
        while not device_mac and self.scan_timeout > 0:
            logger.info("Scanning, timeout = {}s".format(self.scan_timeout))
            scan_time = min(2, self.scan_timeout)
            self.scan_timeout -= scan_time

            devices = await bleak.discover(scan_time)
            for dev in devices:
                logger.debug('Seen: {}'.format(dev.name))
                if dev.name and \
                   dev.name.startswith(self.device_name) and \
                   (self.serial_number is None or
                        dev.name.endswith(self.serial_number)):
                    # Map pretty name to mac-type address
                    device_mac = dev.address
                    full_name = dev.name

        if not device_mac:
            raise JadeError(1, "Unable to locate BLE device",
                            "Device name: {}, Serial number: {}".format(
                              self.device_name, self.serial_number or '<any>'))

        # Remove previous bt/ble pairing data for this device
        if platform.system() == 'Linux':
            command = "bt-device --remove '{}'".format(device_mac)
            process = subprocess.run(command,
                                     shell=True,
                                     stdout=subprocess.DEVNULL)

        # Connect - seems pretty flaky so allow retries
        connected = False
        attempts_remaining = 3
        while not connected:
            try:
                attempts_remaining -= 1
                client = bleak.BleakClient(device_mac)
                logger.info('Connecting to: {} ({})'
                            .format(full_name, device_mac))
                await client.connect()
                connected = await client.is_connected()
                logger.info('Connected: {}'.format(connected))
            except Exception as e:
                logger.warn("BLE connection exception: '{}'".format(e))
                if not attempts_remaining:
                    logger.warn("Exhausted retries - BLE connection failed")
                    raise

        # Peruse services and characteristics
        for service in client.services:
            for char in service.characteristics:
                if 'read' in char.properties:
                    await client.read_gatt_char(char.uuid)

                for descriptor in char.descriptors:
                    await client.read_gatt_descriptor(descriptor.handle)

        # Attach handler to be notified of new data
        def _notification_handler(characteristic, data):
            assert characteristic == JadeBleImpl.IO_RX_CHAR_UUID
            inbufs.append(data)

        await client.start_notify(JadeBleImpl.IO_RX_CHAR_UUID,
                                  _notification_handler)

        # Attach handler to catch unexpected disconnection
        def _disconnection_handler(client):
            logger.error("Unexpected BLE disconnection")

            # Set the client to None - that will cause the receive
            # generator to terminate and not wait forever for data.
            assert client == self.client
            self.client = None

            # Also cancel any running task trying to write data,
            # as otherwise that hangs forever too ...
            if self.write_task:
                self.write_task.cancel()
                self.write_task = None

        client.set_disconnected_callback(_disconnection_handler)

        # Done
        self.client = client
Example #28
0
 def __init__(self, address):
     self._address = address
     self._client = bleak.BleakClient(address)
Example #29
0
async def run_specific_device(addr, debug=False):
    if debug:
        import sys

        # loop.set_debug(True)
        l = logging.getLogger("asyncio")
        l.setLevel(logging.DEBUG)
        h = logging.StreamHandler(sys.stdout)
        h.setLevel(logging.DEBUG)
        l.addHandler(h)
        logger.addHandler(h)

    async with bleak.BleakClient(addr) as client:
        x = await client.is_connected()
        l.info("Connected: {0}".format(x))
        y = await client.get_services()
        y_serv = y.get_service(SERVICE_UUID.lower())
        l.info(y_serv)
        y_char = y.get_characteristic(READ_CHAR_UUID.lower())
        l.info(y_char)
        l.info(y_char.service_uuid)

        #c_serv = y.get_service(CONFIG_SERVICE_UUID.lower())
        #l.info(c_serv)
        #c_char = y.get_characteristic(CONFIG_3_CHAR_UUID.lower())
        #l.info(c_char)
        #l.info(c_char.service_uuid)

        char_1_val = await client.read_gatt_char(CONFIG_1_CHAR_UUID.lower())
        print("Char 1 Value: 0x{0:04X}".format(char_1_val[0]))
        print("Char 1 length: {0}".format(len(char_1_val)))
        char_2_val = await client.read_gatt_char(CONFIG_2_CHAR_UUID.lower())
        print("Char 2 Value: 0x{0:02X} {1:02X} {2:02X} {3:02X}".format(
            char_2_val[0], char_2_val[1], char_2_val[2], char_2_val[3]))
        print("Char 2 length: {0}".format(len(char_2_val)))
        char_3_val = await client.read_gatt_char(CONFIG_3_CHAR_UUID.lower())
        print("Char 3 Value: 0x{0:04X}".format(char_3_val[0]))
        print("Char 3 length: {0}".format(len(char_3_val)))

        if False:
            x = bytearray(randbytes(1))
            print("Writing Char1 to 0x{0:02X}".format(x[0]))
            await client.write_gatt_char(CONFIG_1_CHAR_UUID, x)
            x = bytearray(randbytes(4))
            print("Writing Char2 to 0x{0:02X} {1:02X} {2:02X} {3:02X}".format(
                x[0], x[1], x[2], x[3]))
            await client.write_gatt_char(CONFIG_2_CHAR_UUID, x)
            await asyncio.sleep(0.6)
            print("Done")

        await client.start_notify(READ_CHAR_UUID, notification_handler)
        #  #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0xe,0,0,0,0xff,0xff,0xff,0xff]))
        #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0x21,0,0,0,0,0,0,0]))
        #await asyncio.sleep(0.2)
        #await client.write_gatt_char(WRITE_CHAR_UUID, bytearray([0x0E,0,0,0,0,0,0,0]))
        await asyncio.sleep(25.0)
        await client.stop_notify(READ_CHAR_UUID)

        z = await client.disconnect()
        logger.info("Disconnected: {0}".format(z))
        await asyncio.sleep(1.0)
Example #30
0
async def process_connection(reader: asyncio.streams.StreamReader, writer: asyncio.streams.StreamWriter):
    peer = writer.get_extra_info('peername')

    def callback(char, d):
        if writer.is_closing():
            return
        char = char.encode('ascii')
        writer.write(ResponseOp.ON_DATA + to_bytes(len(char), 2) + char + to_bytes(len(d), 1) + d)
        asyncio.ensure_future(writer.drain())

    print('Incoming connection from %s:%d' % peer)
    adapter: Optional[bleak.BleakClient] = None

    try:
        while True:
            cmd = await reader.readexactly(1)
            if cmd == RequestOp.SCAN:
                timeout = struct.unpack('!f', await reader.readexactly(4))[0]
                try:
                    toys = await bleak.discover(timeout)
                except BaseException as e:
                    err = str(e)[:0xffff].encode('utf_8')
                    writer.write(ResponseOp.ERROR + to_bytes(len(err), 2) + err)
                    await writer.drain()
                    continue
                writer.write(ResponseOp.OK + to_bytes(len(toys), 2))
                await writer.drain()
                for toy in toys:
                    name = toy.name.encode('utf_8')
                    addr = toy.address.encode('ascii')
                    writer.write(to_bytes(len(name), 2) + name + to_bytes(len(addr), 2) + addr)
                    await writer.drain()
            elif cmd == RequestOp.END:
                break
            else:
                seq_size = await reader.readexactly(3)
                seq, size = seq_size[0], to_int(seq_size[1:])
                data = (await reader.readexactly(size)).decode('ascii')
                try:
                    if cmd == RequestOp.INIT:
                        adapter = bleak.BleakClient(data, timeout=5.0)
                        await adapter.connect()
                    elif cmd == RequestOp.SET_CALLBACK:
                        await adapter.start_notify(data, callback)
                    elif cmd == RequestOp.WRITE:
                        size = to_int(await reader.readexactly(2))
                        payload = bytearray(await reader.readexactly(size))
                        await adapter.write_gatt_char(data, payload, True)
                except EOFError:
                    raise
                except BaseException as e:
                    err = str(e)[:0xffff].encode('utf_8')
                    writer.write(ResponseOp.ERROR + to_bytes(len(err), 2) + err + bytes([seq]))
                    await writer.drain()
                    continue
                writer.write(ResponseOp.OK + bytes([seq]))
                await writer.drain()
    finally:
        writer.close()
        if adapter and await adapter.is_connected():
            await adapter.disconnect()
        await writer.wait_closed()
        print('Disconnected from %s:%d' % peer)