class BluetoothCore: def __init__(self, hciIndex = 0): self.settings = BluenetSettings() self.control = ControlHandler(self) self.setup = SetupHandler(self) self.state = StateHandler(self) self.ble = BleHandler(self.settings, hciIndex) def shutDown(self): self.ble.shutDown() def setSettings(self, adminKey, memberKey, guestKey, referenceId = "PythonLib", encryptionEnabled=True): self.settings.loadKeys(encryptionEnabled, adminKey, memberKey, guestKey, referenceId) def loadSettingsFromFile(self, path): fileReader = JsonFileStore(path) data = fileReader.getData() if "admin" not in data: raise BluenetBleException(BluenetError.ADMIN_KEY_REQURED) if "member" not in data: raise BluenetBleException(BluenetError.MEMBER_KEY_REQUIRED) if "guest" not in data: raise BluenetBleException(BluenetError.GUEST_KEY_REQURED) self.setSettings(data["admin"], data["member"], data["guest"]) def connect(self, address): self.ble.connect(address) if self.settings.encryptionEnabled: try: self.control.getAndSetSessionNone() except BluenetBleException as err: # the only relevant error here is this one. If it is any other, the Crownstone is in the wrong mode if err.type is BleError.COULD_NOT_VALIDATE_SESSION_NONCE: raise err def setupCrownstone(self, address, crownstoneId, meshAccessAddress, ibeaconUUID, ibeaconMajor, ibeaconMinor): self.connect(address) self.setup.setup(crownstoneId, meshAccessAddress, ibeaconUUID, ibeaconMajor, ibeaconMinor) self.disconnect() def disconnect(self): self.ble.disconnect() def startScanning(self, scanDuration=3): self.ble.startScanning(scanDuration) def stopScanning(self): self.ble.stopScanning() def getCrownstonesByScanning(self, scanDuration=3): gatherer = Gatherer() subscriptionIdValidated = BluenetEventBus.subscribe(Topics.advertisement, lambda advertisementData: gatherer.handleAdvertisement(advertisementData, True) ) subscriptionIdAll = BluenetEventBus.subscribe(SystemBleTopics.rawAdvertisement, lambda advertisement: gatherer.handleAdvertisement(advertisement.getDictionary(), False) ) self.ble.startScanning(scanDuration=scanDuration) BluenetEventBus.unsubscribe(subscriptionIdValidated) BluenetEventBus.unsubscribe(subscriptionIdAll) return gatherer.getCollection() def isCrownstoneInSetupMode(self, address, scanDuration=3, waitUntilInRequiredMode=False): # print("Checking if it is in setup mode, address", address) checker = SetupChecker(address, waitUntilInRequiredMode) subscriptionId = BluenetEventBus.subscribe(Topics.advertisement, checker.handleAdvertisement) self.ble.startScanning(scanDuration=scanDuration) BluenetEventBus.unsubscribe(subscriptionId) return checker.getResult() def isCrownstoneInNormalMode(self, address, scanDuration=3, waitUntilInRequiredMode=False): # print("Checking if it is in normal mode, address", address) checker = NormalModeChecker(address, waitUntilInRequiredMode) subscriptionId = BluenetEventBus.subscribe(Topics.advertisement, checker.handleAdvertisement) self.ble.startScanning(scanDuration=scanDuration) BluenetEventBus.unsubscribe(subscriptionId) return checker.getResult() def getRssiAverage(self, address, scanDuration=3): # print("Checking if it is in normal mode, address", address) checker = RssiChecker(address) subscriptionId = BluenetEventBus.subscribe(Topics.advertisement, checker.handleAdvertisement) self.ble.startScanning(scanDuration=scanDuration) BluenetEventBus.unsubscribe(subscriptionId) return checker.getResult() def getNearestCrownstone(self, rssiAtLeast=-100, scanDuration=3, returnFirstAcceptable=False, addressesToExclude=[]): return self._getNearest(False, rssiAtLeast, scanDuration, returnFirstAcceptable, False, addressesToExclude) def getNearestValidatedCrownstone(self, rssiAtLeast=-100, scanDuration=3, returnFirstAcceptable=False, addressesToExclude=[]): return self._getNearest(False, rssiAtLeast, scanDuration, returnFirstAcceptable, True, addressesToExclude) def getNearestSetupCrownstone(self, rssiAtLeast=-100, scanDuration=3, returnFirstAcceptable=False, addressesToExclude=[]): return self._getNearest(True, rssiAtLeast, scanDuration, returnFirstAcceptable, True, addressesToExclude) def _getNearest(self, setup, rssiAtLeast, scanDuration, returnFirstAcceptable, validated, addressesToExclude): addressesToExcludeSet = set() for data in addressesToExclude: if isinstance(data, dict): if "address" in data: addressesToExcludeSet.add(data["address"].lower()) else: raise BluenetException(BluenetError.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 = Topics.advertisement if not validated: topic = SystemBleTopics.rawAdvertisement subscriptionId = BluenetEventBus.subscribe(topic, selector.handleAdvertisement) self.ble.startScanning(scanDuration=scanDuration) BluenetEventBus.unsubscribe(subscriptionId) return selector.getNearest()
class BluetoothCore: control = None setup = None config = None state = None mesh = None ble = None def __init__(self, hciIndex=0): self.settings = BluenetSettings() self.control = ControlHandler(self) self.setup = SetupHandler(self) self.state = StateHandler(self) self.ble = BleHandler(self.settings, hciIndex) def shutDown(self): self.ble.shutDown() def setSettings(self, adminKey, memberKey, guestKey, referenceId="PythonLib", encryptionEnabled=True): self.settings.loadKeys(encryptionEnabled, adminKey, memberKey, guestKey, referenceId) def loadSettingsFromFile(self, path): fileReader = JsonFileStore(path) data = fileReader.getData() if "admin" not in data: raise BluenetBleException(BluenetError.ADMIN_KEY_REQURED) if "member" not in data: raise BluenetBleException(BluenetError.MEMBER_KEY_REQUIRED) if "guest" not in data: raise BluenetBleException(BluenetError.GUEST_KEY_REQURED) self.setSettings(data["admin"], data["member"], data["guest"]) def connect(self, address): self.ble.connect(address) if self.settings.encryptionEnabled: try: self.control.getAndSetSessionNone() except BluenetBleException as err: # the only relevant error here is this one. If it is any other, the Crownstone is in the wrong mode if err.type is BleError.COULD_NOT_VALIDATE_SESSION_NONCE: raise err def setupCrownstone(self, address, crownstoneId, meshAccessAddress, ibeaconUUID, ibeaconMajor, ibeaconMinor): self.connect(address) self.setup.setup(crownstoneId, meshAccessAddress, ibeaconUUID, ibeaconMajor, ibeaconMinor) self.disconnect() def disconnect(self): self.ble.disconnect() def startScanning(self, timeout=3): self.ble.startScanning() def stopScanning(self): self.ble.stopScanning() def getNearestCrownstone(self, rssiAtLeast=-100, timeout=3, returnFirstAcceptable=False): return self._getNearest(False, rssiAtLeast, timeout, returnFirstAcceptable, False) def getNearestValidatedCrownstone(self, rssiAtLeast=-100, timeout=3, returnFirstAcceptable=False): return self._getNearest(False, rssiAtLeast, timeout, returnFirstAcceptable, True) def getNearestSetupCrownstone(self, rssiAtLeast=-100, timeout=3, returnFirstAcceptable=False): return self._getNearest(True, rssiAtLeast, timeout, returnFirstAcceptable, True) def _getNearest(self, setup, rssiAtLeast, timeout, returnFirstAcceptable, validated): selector = NearestSelector(setup, rssiAtLeast, returnFirstAcceptable) topic = Topics.advertisement if not validated: topic = SystemBleTopics.rawAdvertisement subscriptionId = BluenetEventBus.subscribe( topic, selector.handleAdvertisement) self.ble.startScanning(timeout=timeout) BluenetEventBus.unsubscribe(subscriptionId) return selector.getNearest()