async def removeMicroapp(self, index): packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_REMOVE).loadByteArray( packet.toBuffer()).getPacket() await self._writeControlAndWaitForSuccess(controlPacket) _LOGGER.info(f"Removed app {index}")
def resetCrownstone(self): """ Reset the Crownstone :return: """ resetPacket = ControlPacket(ControlType.RESET).getPacket() self._send(UartTxType.CONTROL, resetPacket)
def toggleIGBTs(self, isOn): val = 0 if isOn: val = 100 switchPacket = ControlPacket( ControlType.PWM).loadUInt8(val).getPacket() self._send(UartTxType.CONTROL, switchPacket)
def toggleRelay(self, isOn): val = 0 if isOn: val = 1 switchPacket = ControlPacket( ControlType.RELAY).loadUInt8(val).getPacket() self._send(UartTxType.CONTROL, switchPacket)
async def uploadMicroappChunk(self, index: int, data: bytearray, offset: int): _LOGGER.info( f"Upload microapp chunk index={index} offset={offset} size={len(data)}" ) header = MicroappHeaderPacket(appIndex=index) packet = MicroappUploadPacket(header, offset, data) controlPacket = ControlPacket( ControlType.MICROAPP_UPLOAD).loadByteArray( packet.toBuffer()).getPacket() def handleResult(notificationData): result = ResultPacket(notificationData) if result.valid: if result.resultCode == ResultValue.WAIT_FOR_SUCCESS: _LOGGER.info( "Waiting for data to be stored on Crownstone.") return ProcessType.CONTINUE elif result.resultCode == ResultValue.SUCCESS or result.resultCode == ResultValue.SUCCESS_NO_CHANGE: _LOGGER.info("Data stored.") return ProcessType.FINISHED else: _LOGGER.warning(f"Failed: {result.resultCode}") return ProcessType.ABORT_ERROR else: _LOGGER.warning("Invalid result.") return ProcessType.ABORT_ERROR await self.core.ble.setupNotificationStream( CSServices.CrownstoneService, CrownstoneCharacteristics.Result, lambda: self._writeControlPacket(controlPacket), lambda notification: handleResult(notification), 5) _LOGGER.info(f"uploaded chunk offset={offset}")
def toggleAllowDimming(self, isOn): val = 0 if isOn: val = 1 instructionPacket = ControlPacket( ControlType.ALLOW_DIMMING).loadUInt8(val).getPacket() self._send(UartTxType.CONTROL, instructionPacket)
def getPowerSamplesRequestPacket(samplesType, index): buffer = BufferWriter() buffer.putUInt8(samplesType) buffer.putUInt8(index) data = buffer.getBuffer() return ControlPacket( ControlType.GET_POWER_SAMPLES).loadByteArray(data).serialize()
async def removeMicroapp(self, index): packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_REMOVE).loadByteArray( packet.toBuffer()).getPacket() def handleResult(notificationData): result = ResultPacket(notificationData) if result.valid: if result.resultCode == ResultValue.WAIT_FOR_SUCCESS: _LOGGER.info( "Waiting for data to be erased on Crownstone.") return ProcessType.CONTINUE elif result.resultCode == ResultValue.SUCCESS or result.resultCode == ResultValue.SUCCESS_NO_CHANGE: _LOGGER.info("Data erased.") return ProcessType.FINISHED else: _LOGGER.warning(f"Failed: {result.resultCode}") return ProcessType.ABORT_ERROR else: _LOGGER.warning("Invalid result.") return ProcessType.ABORT_ERROR await self.core.ble.setupNotificationStream( CSServices.CrownstoneService, CrownstoneCharacteristics.Result, lambda: self._writeControlPacket(controlPacket), lambda notification: handleResult(notification), 5) _LOGGER.info(f"Removed app {index}")
def _switch_crownstone(self, crownstone_id: int, switch_val: int): """ :param crownstone_id: :param switch_val: 0% .. 100% or special value (SwitchValSpecial). :return: """ # create a stone switch state packet to go into the multi switch stoneSwitchPacket = StoneMultiSwitchPacket(crownstone_id, switch_val) # wrap it in a mesh multi switch packet meshMultiSwitchPacket = MeshMultiSwitchPacket([stoneSwitchPacket ]).getPacket() # wrap that in a control packet controlPacket = ControlPacket(ControlType.MULTISWITCH).loadByteArray( meshMultiSwitchPacket).getPacket() # wrap that in a uart message uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() # finally wrap it in a uart wrapper packet uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() # send over uart UartEventBus.emit(SystemTopics.uartWriteData, uartPacket)
async def _command_via_mesh_broadcast(self, packet: bytearray): # this is only for time and noop # broadcast to all: # value: 1 corePacket = MeshBroadcastPacket(packet).getPacket() controlPacket = ControlPacket( ControlType.MESH_COMMAND).loadByteArray(corePacket).getPacket() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() resultCollector = Collector(timeout=2, topic=SystemTopics.resultPacket) # send the message to the Crownstone UartEventBus.emit(SystemTopics.uartWriteData, uartPacket) # wait for the collectors to fill commandResultData = await resultCollector.receive() if commandResultData is not None: if commandResultData.resultCode is ResultValue.BUSY: await asyncio.sleep(0.2) return await self._command_via_mesh_broadcast(packet) elif commandResultData.resultCode is not ResultValue.SUCCESS: raise CrownstoneException(commandResultData.resultCode, "Command has failed.") await asyncio.sleep(0.1)
def echo(self, string): controlPacket = ControlPacket( ControlType.UART_MESSAGE).loadString(string).getPacket() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() UartEventBus.emit(SystemTopics.uartWriteData, uartPacket)
def getIBeaconConfigIdPacket(id, timestamp, interval): data = [] data.append(id) data += Conversion.uint32_to_uint8_array(timestamp) data += Conversion.uint16_to_uint8_array(interval) return ControlPacket( ControlType.SET_IBEACON_CONFIG_ID).loadByteArray(data).serialize()
def getSetTimePacket(time): """ This is a LOCAL timestamp since epoch in seconds so if you live in GMT + 1 add 3600 to the timestamp :param time: :return: """ return ControlPacket(ControlType.SET_TIME).loadUInt32(time).serialize()
def getRelaySwitchPacket(turnOn: bool): """ :param turnOn: True to turn relay on. """ switchVal = 0 if turnOn: switchVal = 1 return ControlPacket( ControlType.RELAY).loadUInt8(switchVal).serialize()
async def reset_rssi_between_stones(self, crownstone_uid_array: List[int] = None ): control_packet = ControlPacket(ControlType.RESET_RSSI_BETWEEN_STONES) if (crownstone_uid_array == None): return await self._command_via_mesh_broadcast( control_packet.serialize()) else: return await self._command_via_mesh_broadcast_acked( crownstone_uid_array, control_packet.serialize())
async def getMicroappInfo(self) -> MicroappInfoPacket: controlPacket = ControlPacket( ControlType.MICROAPP_GET_INFO).getPacket() result = await self.core.ble.setupSingleNotification( CSServices.CrownstoneService, CrownstoneCharacteristics.Result, lambda: self._writeControlPacket(controlPacket)) _LOGGER.info(f"getMicroappInfo {result}") resultPacket = ResultPacket(result) _LOGGER.info(f"getMicroappInfo {resultPacket}") infoPacket = MicroappInfoPacket(resultPacket.payload) return infoPacket
async def enableMicroapp(self, index): packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_ENABLE).loadByteArray( packet.toBuffer()).getPacket() result = await self.core.ble.setupSingleNotification( CSServices.CrownstoneService, CrownstoneCharacteristics.Result, lambda: self._writeControlPacket(controlPacket)) resultPacket = ResultPacket(result) if resultPacket.resultCode != ResultValue.SUCCESS: raise CrownstoneException(CrownstoneError.RESULT_NOT_SUCCESS, f"result={resultPacket.resultCode}")
def getLockSwitchPacket(lock: bool): """ :param lock: bool :return: """ lockByte = 0 if lock: lockByte = 1 return ControlPacket( ControlType.LOCK_SWITCH).loadUInt8(lockByte).serialize()
async def uploadMicroappChunk(self, index: int, data: bytearray, offset: int): _LOGGER.info( f"Upload microapp chunk index={index} offset={offset} size={len(data)}" ) header = MicroappHeaderPacket(appIndex=index) packet = MicroappUploadPacket(header, offset, data) controlPacket = ControlPacket( ControlType.MICROAPP_UPLOAD).loadByteArray( packet.toBuffer()).getPacket() await self._writeControlAndWaitForSuccess(controlPacket) _LOGGER.info(f"uploaded chunk offset={offset}")
def getAllowDimmingPacket(allow: bool): """ :param allow: bool :return: """ allowByte = 0 if allow: allowByte = 1 return ControlPacket( ControlType.ALLOW_DIMMING).loadUInt8(allowByte).serialize()
def getRamStats(): controlPacket = ControlPacket(ControlType.GET_RAM_STATS).getPacket() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() try: result = UartWriter(uartPacket).write_with_result_sync() if result.resultCode is ResultValue.SUCCESS: return RamStatsPacket(result.payload) logging.log(logging.WARN, f"Get ram stats failed, result={result}") except CrownstoneException as e: logging.log(logging.WARN, f"Get ram stats failed: {e}") return None
def uart_echo(self, payloadString): # wrap that in a control packet controlPacket = ControlPacket( ControlType.UART_MESSAGE).loadString(payloadString).getPacket() # wrap that in a uart message uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() # finally, wrap it in an uart wrapper packet uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() # send over uart result = UartWriter(uartPacket).write_sync()
def validate_microapp(self, index: int): """ validate the binary of a microapp saved in Bluenet flash memory. Return True if message is send correctly, it doesn't check if the command is set correctly in Bluenet. For now only an index of 0 can be given, since Bluenet only supports a single app to run. """ packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_VALIDATE).loadByteArray( packet.serialize()).serialize() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).serialize() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).serialize() UartWriter(uartPacket).write_sync()
def disable_microapp(self, index: int): """ Disable a running microapp in Bluenet by removing it from RAM. Return True if message is send correctly, it doesn't check if the command is set correctly in Bluenet. For now only an index of 0 can be given, since Bluenet only supports a single app to run. """ packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_DISABLE).loadByteArray( packet.serialize()).serialize() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).serialize() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).serialize() UartWriter(uartPacket).write_sync()
def enable_microapp(self, index: int): """ Enable microapp in Bluenet and load it in RAM. Return True if message is send correctly, it doesn't check if the command is set correctly in Bluenet. For now only an index of 0 can be given, since Bluenet only supports a single app to run. It is recommended to run the validation function before enabling the microapp to make sure a microapp is able to run. """ packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_ENABLE).loadByteArray( packet.serialize()).serialize() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).serialize() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).serialize() UartWriter(uartPacket).write_sync()
def getSetupPacket(crownstoneId: int, sphereId: int, adminKey, memberKey, basicKey, serviceDataKey, localizationKey, meshDeviceKey, meshAppKey, meshNetworkKey, ibeaconUUID: str, ibeaconMajor: int, ibeaconMinor: int): """ :param crownstoneId: uint8 number :param sphereId: uint8 number :param adminKey: byteString (no conversion required) :param memberKey: byteString (no conversion required) :param basicKey: byteString (no conversion required) :param serviceDataKey: byteString (no conversion required) :param localizationKey: byteString (no conversion required) :param meshDeviceKey: byteString (no conversion required) :param meshAppKey: byteString (no conversion required) :param meshNetworkKey: byteString (no conversion required) :param ibeaconUUID: string (ie. "1843423e-e175-4af0-a2e4-31e32f729a8a") :param ibeaconMajor: uint16 number :param ibeaconMinor: uint16 number :return: """ data = [] data.append(crownstoneId) data.append(sphereId) data += list(adminKey) data += list(memberKey) data += list(basicKey) data += list(serviceDataKey) data += list(localizationKey) MDKey = meshDeviceKey if type(meshDeviceKey) is str: MDKey = Conversion.ascii_or_hex_string_to_16_byte_array( meshDeviceKey) data += list(MDKey) data += list(meshAppKey) data += list(meshNetworkKey) data += Conversion.ibeaconUUIDString_to_reversed_uint8_array( ibeaconUUID) data += Conversion.uint16_to_uint8_array(ibeaconMajor) data += Conversion.uint16_to_uint8_array(ibeaconMinor) return ControlPacket(ControlType.SETUP).loadByteArray(data).serialize()
async def _command_via_mesh_broadcast_acked( self, crownstone_uid_array: List[int], packet: bytearray) -> MeshResult: # this is only for the set_iBeacon_config_id # broadcast to all, but retry until ID's in list have acked or timeout # value: 3 corePacket = MeshBroadcastAckedPacket(crownstone_uid_array, packet).getPacket() controlPacket = ControlPacket( ControlType.MESH_COMMAND).loadByteArray(corePacket).getPacket() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() resultCollector = Collector(timeout=2, topic=SystemTopics.resultPacket) individualCollector = BatchCollector( timeout=15, topic=SystemTopics.meshResultPacket) finalCollector = Collector(timeout=15, topic=SystemTopics.meshResultFinalPacket) # send the message to the Crownstone UartEventBus.emit(SystemTopics.uartWriteData, uartPacket) # wait for the collectors to fill commandResultData = await resultCollector.receive() if commandResultData is not None: if commandResultData.resultCode is ResultValue.BUSY: await asyncio.sleep(0.2) return await self._command_via_mesh_broadcast_acked( crownstone_uid_array, packet) elif commandResultData.resultCode is not ResultValue.SUCCESS: raise CrownstoneException(commandResultData.resultCode, "Command has failed.") return await self._handleCollectors(crownstone_uid_array, individualCollector, finalCollector)
async def _set_state_via_mesh_acked(self, crownstone_id: int, packet: bytearray) -> MeshResult: # 1:1 message to N crownstones with acks (only N = 1 supported for now) # flag value: 2 corePacket = MeshSetStatePacket(crownstone_id, packet).getPacket() controlPacket = ControlPacket( ControlType.MESH_COMMAND).loadByteArray(corePacket).getPacket() uartMessage = UartMessagePacket(UartTxType.CONTROL, controlPacket).getPacket() uartPacket = UartWrapperPacket(UartMessageType.UART_MESSAGE, uartMessage).getPacket() resultCollector = Collector(timeout=2, topic=SystemTopics.resultPacket) individualCollector = BatchCollector( timeout=15, topic=SystemTopics.meshResultPacket) finalCollector = Collector(timeout=15, topic=SystemTopics.meshResultFinalPacket) # send the message to the Crownstone UartEventBus.emit(SystemTopics.uartWriteData, uartPacket) # wait for the collectors to fill commandResultData = await resultCollector.receive() if commandResultData is not None: if commandResultData.resultCode is ResultValue.BUSY: await asyncio.sleep(0.2) return await self._set_state_via_mesh_acked( crownstone_id, packet) elif commandResultData.resultCode is not ResultValue.SUCCESS: raise CrownstoneException(commandResultData.resultCode, "Command has failed.") return await self._handleCollectors([crownstone_id], individualCollector, finalCollector)
async def enableMicroapp(self, index): packet = MicroappHeaderPacket(index) controlPacket = ControlPacket( ControlType.MICROAPP_ENABLE).loadByteArray( packet.toBuffer()).getPacket() await self._writeControlAndGetResult(controlPacket)
async def send_no_op(self): no_op_packet = ControlPacket(ControlType.NO_OPERATION) await self._command_via_mesh_broadcast(no_op_packet.getPacket())