async def read_gatt_char(self, char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID], use_cached=False, **kwargs) -> bytearray: """Perform read operation on the specified GATT characteristic. Args: char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to read from, specified by either integer handle, UUID or directly by the BleakGATTCharacteristic object representing it. use_cached (bool): `False` forces Windows to read the value from the device again and not use its own cached value. Defaults to `False`. Returns: (bytearray) The read data. """ if not isinstance(char_specifier, BleakGATTCharacteristic): characteristic = self.services.get_characteristic(char_specifier) else: characteristic = char_specifier if not characteristic: raise BleakError( "Characteristic {0} was not found!".format(char_specifier)) read_result = await wrap_IAsyncOperation( IAsyncOperation[GattReadResult](characteristic.obj.ReadValueAsync( BluetoothCacheMode. Cached if use_cached else BluetoothCacheMode.Uncached)), return_type=GattReadResult, loop=self.loop, ) if read_result.Status == GattCommunicationStatus.Success: reader = DataReader.FromBuffer(IBuffer(read_result.Value)) output = Array.CreateInstance(Byte, reader.UnconsumedBufferLength) reader.ReadBytes(output) value = bytearray(output) logger.debug("Read Characteristic {0} : {1}".format( characteristic.uuid, value)) else: if read_result.Status == GattCommunicationStatus.ProtocolError: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X})" .format( characteristic.uuid, _communication_statues.get(read_result.Status, ""), read_result.ProtocolError, )) else: raise BleakError( "Could not read characteristic value for {0}: {1}".format( characteristic.uuid, _communication_statues.get(read_result.Status, ""), )) return value
async def read_gatt_descriptor(self, handle: int, use_cached=False, **kwargs) -> bytearray: """Perform read operation on the specified GATT descriptor. Args: handle (int): The handle of the descriptor to read from. use_cached (bool): `False` forces Windows to read the value from the device again and not use its own cached value. Defaults to `False`. Returns: (bytearray) The read data. """ descriptor = self.services.get_descriptor(handle) if not descriptor: raise BleakError( "Descriptor with handle {0} was not found!".format(handle)) read_result = await wrap_IAsyncOperation( IAsyncOperation[GattReadResult](descriptor.obj.ReadValueAsync( BluetoothCacheMode. Cached if use_cached else BluetoothCacheMode.Uncached)), return_type=GattReadResult, loop=self.loop, ) if read_result.Status == GattCommunicationStatus.Success: reader = DataReader.FromBuffer(IBuffer(read_result.Value)) output = Array.CreateInstance(Byte, reader.UnconsumedBufferLength) reader.ReadBytes(output) value = bytearray(output) logger.debug("Read Descriptor {0} : {1}".format(handle, value)) else: if read_result.Status == GattCommunicationStatus.ProtocolError: raise BleakDotNetTaskError( "Could not get GATT characteristics for {0}: {1} (Error: 0x{2:02X})" .format( descriptor.uuid, _communication_statues.get(read_result.Status, ""), read_result.ProtocolError, )) else: raise BleakError( "Could not read Descriptor value for {0}: {1}".format( descriptor.uuid, _communication_statues.get(read_result.Status, ""), )) return value
def parse_eventargs(event_args): bdaddr = _format_bdaddr(event_args.BluetoothAddress) uuids = [] for u in event_args.Advertisement.ServiceUuids: uuids.append(u.ToString()) data = {} for m in event_args.Advertisement.ManufacturerData: md = IBuffer(m.Data) b = Array.CreateInstance(Byte, md.Length) reader = DataReader.FromBuffer(md) reader.ReadBytes(b) data[m.CompanyId] = bytes(b) local_name = event_args.Advertisement.LocalName return BLEDevice(bdaddr, local_name, event_args, uuids=uuids, manufacturer_data=data)
async def read_gatt_char(self, _uuid: str, use_cached=False, **kwargs) -> bytearray: """Perform read operation on the specified GATT characteristic. Args: _uuid (str or UUID): The uuid of the characteristics to read from. use_cached (bool): `False` forces Windows to read the value from the device again and not use its own cached value. Defaults to `False`. Returns: (bytearray) The read data. """ characteristic = self.services.get_characteristic(str(_uuid)) if not characteristic: raise BleakError("Characteristic {0} was not found!".format(_uuid)) read_result = await wrap_IAsyncOperation( IAsyncOperation[GattReadResult]( characteristic.obj.ReadValueAsync( BluetoothCacheMode.Cached if use_cached else BluetoothCacheMode.Uncached ) ), return_type=GattReadResult, loop=self.loop, ) if read_result.Status == GattCommunicationStatus.Success: reader = DataReader.FromBuffer(IBuffer(read_result.Value)) output = Array.CreateInstance(Byte, reader.UnconsumedBufferLength) reader.ReadBytes(output) value = bytearray(output) logger.debug("Read Characteristic {0} : {1}".format(_uuid, value)) else: raise BleakError( "Could not read characteristic value for {0}: {1}".format( characteristic.uuid, read_result.Status ) ) return value
def AdvertisementWatcher_Received(sender, e): if sender == watcher: # logger.debug("Received {0}.".format(_format_event_args(e))) l_bdaddr = _format_bdaddr(e.BluetoothAddress) l_uuids = [] for l_u in e.Advertisement.ServiceUuids: l_uuids.append(l_u.ToString()) l_data = {} for l_m in e.Advertisement.ManufacturerData: l_md = IBuffer(l_m.Data) l_b = Array.CreateInstance(Byte, l_md.Length) l_reader = DataReader.FromBuffer(l_md) l_reader.ReadBytes(l_b) l_data[l_m.CompanyId] = bytes(l_b) local_name = e.Advertisement.LocalName logger.debug(f'>>> bdaddr:{l_bdaddr} local_name:{local_name} mfdata:{l_data}') if q: q.put(BLEDevice( l_bdaddr, local_name, e, uuids=l_uuids, manufacturer_data=l_data, ))
async def discover( timeout: float = 5.0, loop: AbstractEventLoop = None, **kwargs ) -> List[BLEDevice]: """Perform a Bluetooth LE Scan using Windows.Devices.Bluetooth.Advertisement Args: timeout (float): Time to scan for. loop (Event Loop): The event loop to use. Keyword Args: SignalStrengthFilter (Windows.Devices.Bluetooth.BluetoothSignalStrengthFilter): A BluetoothSignalStrengthFilter object used for configuration of Bluetooth LE advertisement filtering that uses signal strength-based filtering. AdvertisementFilter (Windows.Devices.Bluetooth.Advertisement.BluetoothLEAdvertisementFilter): A BluetoothLEAdvertisementFilter object used for configuration of Bluetooth LE advertisement filtering that uses payload section-based filtering. string_output (bool): If set to false, ``discover`` returns .NET device objects instead. Returns: List of strings or objects found. """ signal_strength_filter = kwargs.get("SignalStrengthFilter", None) advertisement_filter = kwargs.get("AdvertisementFilter", None) loop = loop if loop else asyncio.get_event_loop() watcher = BluetoothLEAdvertisementWatcher() devices = {} scan_responses = {} def _format_bdaddr(a): return ":".join("{:02X}".format(x) for x in a.to_bytes(6, byteorder="big")) def _format_event_args(e): try: return "{0}: {1}".format( _format_bdaddr(e.BluetoothAddress), e.Advertisement.LocalName or "Unknown", ) except Exception: return e.BluetoothAddress def AdvertisementWatcher_Received(sender, e): if sender == watcher: logger.debug("Received {0}.".format(_format_event_args(e))) if e.AdvertisementType == BluetoothLEAdvertisementType.ScanResponse: if e.BluetoothAddress not in scan_responses: scan_responses[e.BluetoothAddress] = e else: if e.BluetoothAddress not in devices: devices[e.BluetoothAddress] = e def AdvertisementWatcher_Stopped(sender, e): if sender == watcher: logger.debug( "{0} devices found. Watcher status: {1}.".format( len(devices), watcher.Status ) ) watcher.Received += AdvertisementWatcher_Received watcher.Stopped += AdvertisementWatcher_Stopped watcher.ScanningMode = BluetoothLEScanningMode.Active if signal_strength_filter is not None: watcher.SignalStrengthFilter = signal_strength_filter if advertisement_filter is not None: watcher.AdvertisementFilter = advertisement_filter # Watcher works outside of the Python process. watcher.Start() await asyncio.sleep(timeout, loop=loop) watcher.Stop() try: watcher.Received -= AdvertisementWatcher_Received watcher.Stopped -= AdvertisementWatcher_Stopped except Exception as e: logger.debug("Could not remove event handlers: {0}...".format(e)) found = [] for d in list(devices.values()): bdaddr = _format_bdaddr(d.BluetoothAddress) uuids = [] for u in d.Advertisement.ServiceUuids: uuids.append(u.ToString()) data = {} for m in d.Advertisement.ManufacturerData: md = IBuffer(m.Data) b = Array.CreateInstance(Byte, md.Length) reader = DataReader.FromBuffer(md) reader.ReadBytes(b) data[m.CompanyId] = bytes(b) local_name = d.Advertisement.LocalName if not local_name and d.BluetoothAddress in scan_responses: local_name = scan_responses[d.BluetoothAddress].Advertisement.LocalName found.append( BLEDevice(bdaddr, local_name, d, uuids=uuids, manufacturer_data=data,) ) return found
def __init__(self, buffer_com_object): self.reader = None self.buffer = IBuffer(buffer_com_object)
async def discover(timeout: float = 5.0, loop: AbstractEventLoop = None, **kwargs) -> List[BLEDevice]: """Perform a Bluetooth LE Scan. Args: timeout (float): Time to scan for. loop (Event Loop): The event loop to use. Keyword Args: string_output (bool): If set to false, ``discover`` returns .NET device objects instead. Returns: List of strings or objects found. """ loop = loop if loop else asyncio.get_event_loop() watcher = BluetoothLEAdvertisementWatcher() devices = {} def _format_bdaddr(a): return ":".join("{:02X}".format(x) for x in a.to_bytes(6, byteorder="big")) def _format_event_args(e): try: return "{0}: {1}".format( _format_bdaddr(e.BluetoothAddress), e.Advertisement.LocalName or "Unknown", ) except Exception: return e.BluetoothAddress def AdvertisementWatcher_Received(sender, e): if sender == watcher: logger.debug("Received {0}.".format(_format_event_args(e))) if e.BluetoothAddress not in devices: devices[e.BluetoothAddress] = e def AdvertisementWatcher_Stopped(sender, e): if sender == watcher: logger.debug("{0} devices found. Watcher status: {1}.".format( len(devices), watcher.Status)) watcher.Received += AdvertisementWatcher_Received watcher.Stopped += AdvertisementWatcher_Stopped # Watcher works outside of the Python process. watcher.Start() await asyncio.sleep(timeout, loop=loop) watcher.Stop() try: watcher.Received -= AdvertisementWatcher_Received watcher.Stopped -= AdvertisementWatcher_Stopped except Exception as e: logger.debug("Could not remove event handlers: {0}...".format(e)) found = [] for d in devices.values(): bdaddr = _format_bdaddr(d.BluetoothAddress) uuids = [] for u in d.Advertisement.ServiceUuids: uuids.append(u.ToString()) data = {} for m in d.Advertisement.ManufacturerData: md = IBuffer(m.Data) b = Array.CreateInstance(Byte, md.Length) reader = DataReader.FromBuffer(md) reader.ReadBytes(b) data[m.CompanyId] = bytes(b) found.append( BLEDevice(bdaddr, d.Advertisement.LocalName, d, uuids=uuids, manufacturer_data=data)) return found