async def _getNearest(self, setup, rssiAtLeast, scanDuration, returnFirstAcceptable, validated, addressesToExclude) -> ScanData or None: addressesToExcludeSet = set() if addressesToExclude is not None: for data in addressesToExclude: if hasattr(data, 'address'): addressesToExcludeSet.add(data.address.lower()) elif isinstance(data, dict): if "address" in data: addressesToExcludeSet.add(data["address"].lower()) else: raise CrownstoneException( CrownstoneError.INVALID_ADDRESS, "Addresses to Exclude is either an array of addresses (like 'f7:19:a4:ef:ea:f6') or an array of dicts with the field 'address'" ) else: addressesToExcludeSet.add(data.lower()) selector = NearestSelector(setup, rssiAtLeast, returnFirstAcceptable, addressesToExcludeSet) topic = BleTopics.advertisement if not validated: topic = BleTopics.rawAdvertisement subscriptionId = BleEventBus.subscribe( topic, lambda scanData: selector.handleAdvertisement(scanData)) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionId) return selector.getNearest()
async def waitForMode(self, address, requiredMode: CrownstoneOperationMode, scanDuration=5): """ This will wait until it has received an advertisement from the Crownstone with the specified address. Once it has received an advertisement, it knows the mode. We will scan for the scanDuration amount of seconds or until the Crownstone is in the required mode. It can throw the following CrownstoneBleException - BleError.NO_SCANS_RECEIVED We have not received any scans from this Crownstone, and can't say anything about it's state. - BleError.DIFFERENT_MODE_THAN_REQUIRED During the {scanDuration} seconds of scanning, the Crownstone was not in the required mode. """ _LOGGER.debug( f"waitForMode address={address} requiredMode={requiredMode} scanDuration={scanDuration}" ) checker = ModeChecker(address, requiredMode, True) subscriptionId = BleEventBus.subscribe( BleTopics.rawAdvertisement, lambda scanData: checker.handleAdvertisement(scanData)) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionId) result = checker.getResult() if result is None: raise CrownstoneBleException( BleError.NO_SCANS_RECEIVED, f'During the {scanDuration} seconds of scanning, no advertisement was received from this address.' ) if result != requiredMode: raise CrownstoneBleException( BleError.DIFFERENT_MODE_THAN_REQUIRED, f'During the {scanDuration} seconds of scanning, the Crownstone was not in the required mode..' )
async def getMode(self, address, scanDuration=3) -> CrownstoneOperationMode: """ This will wait until it has received an advertisement from the Crownstone with the specified address. Once it has received an advertisement, it knows the mode. We will return once we know. It can throw the following CrownstoneBleException - BleError.NO_SCANS_RECEIVED We have not received any scans from this Crownstone, and can't say anything about it's state. """ _LOGGER.debug(f"getMode address={address} scanDuration={scanDuration}") checker = ModeChecker(address, None) subscriptionId = BleEventBus.subscribe( BleTopics.rawAdvertisement, lambda scanData: checker.handleAdvertisement(scanData)) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionId) result = checker.getResult() if result is None: raise CrownstoneBleException( BleError.NO_SCANS_RECEIVED, f'During the {scanDuration} seconds of scanning, no advertisement was received from this address.' ) return result
async def isCrownstoneInSetupMode(self, address: str, scanDuration=3, waitUntilInSetupMode=False) -> bool: _LOGGER.warning( "isCrownstoneInSetupMode is deprecated. Will be removed in v3. Use either getMode or waitForMode instead." ) """ This will wait until it has received an advertisement from the Crownstone with the specified address. Once it has received an advertisement, it knows the mode. With default value for waitUntilInSetupMode (False), it will return True if the Crownstone is in setup mode, False if it isn't. You can use the boolean waitUntilInSetupMode to have it ignore advertisements from this Crownstone in other modes than setup mode. It can throw the following CrownstoneBleException - BleError.NO_SCANS_RECEIVED We have not received any scans from this Crownstone, and can't say anything about it's state. """ _LOGGER.debug( f"isCrownstoneInSetupMode address={address} scanDuration={scanDuration} waitUntilInSetupMode={waitUntilInSetupMode}" ) checker = ModeChecker(address, CrownstoneOperationMode.SETUP, waitUntilInSetupMode) subscriptionId = BleEventBus.subscribe(BleTopics.advertisement, checker.handleAdvertisement) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionId) result = checker.getResult() if result is None: raise CrownstoneBleException( BleError.NO_SCANS_RECEIVED, f'During the {scanDuration} seconds of scanning, no advertisement was received from this address.' ) return result
async def getRssiAverage(self, address, scanDuration=3): checker = RssiChecker(address) subscriptionId = BleEventBus.subscribe( BleTopics.rawAdvertisement, lambda scanData: checker.handleAdvertisement(scanData)) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionId) return checker.getResult()
async def getCrownstonesByScanning(self, scanDuration=3): gatherer = Gatherer() subscriptionIdAll = BleEventBus.subscribe( BleTopics.rawAdvertisement, lambda scanData: gatherer.handleAdvertisement(scanData)) await self.ble.scan(duration=scanDuration) BleEventBus.unsubscribe(subscriptionIdAll) return gatherer.getCollection()
async def waitForPeripheralToDisconnect(self, timeout: int = 10): if self.activeClient is not None: if await self.activeClient.isConnected(): waiting = True def disconnectListener(data): nonlocal waiting waiting = False listenerId = BleEventBus.subscribe( SystemBleTopics.forcedDisconnect, disconnectListener) timer = 0 while waiting and timer < 10: await asyncio.sleep(0.1) timer += 0.1 BleEventBus.unsubscribe(listenerId) self.activeClient = None
async def shutDown(self): for subscriptionId in self.subscriptionIds: BleEventBus.unsubscribe(subscriptionId) await self.disconnect() await self.stopScanning()