def getSetupPacket(commandType, crownstoneId, adminKey, memberKey, guestKey, meshAccessAddress, ibeaconUUID, ibeaconMajor, ibeaconMinor): """ :param commandType: uint8 number :param crownstoneId: uint8 number :param adminKey: byteString (no conversion required) :param memberKey: byteString (no conversion required) :param guestKey: byteString (no conversion required) :param meshAccessAddress: hexstring :param ibeaconUUID: string (ie. "1843423e-e175-4af0-a2e4-31e32f729a8a") :param ibeaconMajor: uint16 number :param ibeaconMinor: uint16 number :return: """ data = [] data.append(commandType) data.append(crownstoneId) data += list(adminKey) data += list(memberKey) data += list(guestKey) if type(meshAccessAddress) is str: data += Conversion.hex_string_to_uint8_array(meshAccessAddress) else: data += Conversion.uint32_to_uint8_array(meshAccessAddress) 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).getPacket()
def getPacket(self): # get the length of the payload before escaping baseLength = len(self.payload) # construct the basePacket, which is used for CRC calculation basePacket = [] basePacket += Conversion.uint16_to_uint8_array(self.opCode) basePacket += Conversion.uint16_to_uint8_array(baseLength) basePacket += self.payload # calculate the CRC of the packet so far baseCrc = UartUtil.crc16_ccitt(basePacket) # append the CRC to the base packet to escape the entire thing basePacket += Conversion.uint16_to_uint8_array(baseCrc) # escape everything except the START_TOKEN escapedPayload = self.escapeCharacters(basePacket) uartPacket = [] uartPacket.append(START_TOKEN) uartPacket += escapedPayload return uartPacket pass
def encrypt(self, data: int) -> int: # alteration to accept numbers instead of bytes data = Conversion.uint32_to_uint16_reversed_array(data) data = bytes(Conversion.uint16_array_to_uint8_array(data)) blocksize = self.blocksize key = self.key rounds = self.rounds w = blocksize // 2 b = blocksize // 8 expanded_key = _expand_key(key, w, rounds) index = b chunk = data[:index] out = [] while chunk: chunk = chunk.ljust(b, b"\x00") # padding with 0 bytes if not large enough encrypted_chunk = _encrypt_block(chunk, expanded_key, blocksize, rounds) out.append(encrypted_chunk) chunk = data[index : index + b] # Read in blocksize number of bytes index += b result = b"".join(out) result = Conversion.uint8_array_to_uint16_array(result) result = Conversion.uint16_reversed_array_to_uint32(result) return result
def decrypt(self, data: int) -> bytes: data = Conversion.uint32_to_uint16_reversed_array(data) data = bytes(Conversion.uint16_array_to_uint8_array(data)) blocksize = self.blocksize key = self.key rounds = self.rounds w = blocksize // 2 b = blocksize // 8 expanded_key = _expand_key(key, w, rounds) index = b chunk = data[:index] out = [] while chunk: decrypted_chunk = _decrypt_block(chunk, expanded_key, blocksize, rounds) chunk = data[index : index + b] # Read in blocksize number of bytes if not chunk: decrypted_chunk = decrypted_chunk.rstrip(b"\x00") index += b out.append(decrypted_chunk) result = b"".join(out) result = Conversion.uint8_array_to_uint16_array(result) result = Conversion.uint16_reversed_array_to_uint32(result) return result
def getPacket(self): arr = [] arr += Conversion.uint16_to_uint8_array(self.type) arr += Conversion.uint16_to_uint8_array(self.length + 2) # 2 for the ID size arr += self.payload # this is the state type arr += Conversion.uint16_to_uint8_array(self.id) return arr
def load(self, data): minSize = 6 if len(data) >= minSize: self.commandTypeUInt16 = Conversion.uint8_array_to_uint16( [data[0], data[1]]) resultNumber = Conversion.uint8_array_to_uint16([data[2], data[3]]) if ControlType.has_value(self.commandTypeUInt16 ) and ResultValue.has_value(resultNumber): self.commandType = ControlType(self.commandTypeUInt16) self.resultCode = ResultValue(resultNumber) self.size = Conversion.uint8_array_to_uint16( [data[4], data[5]]) totalSize = minSize + self.size if len(data) >= totalSize: if self.size == 0: return for i in range(minSize, totalSize): self.payload.append(data[i]) else: self.valid = False else: self.valid = False else: self.valid = False
def parseErrorState(self, meshErrorState): self.crownstoneId = meshErrorState[0] self.hasError = True self.errorMode = True self.errorsBitmask = Conversion.uint8_array_to_uint32([ meshErrorState[1], meshErrorState[2], meshErrorState[3], meshErrorState[4] ]) self.errorTimestamp = Conversion.uint8_array_to_uint32([ meshErrorState[5], meshErrorState[6], meshErrorState[7], meshErrorState[8] ]) self.flagsBitmask = meshErrorState[9] self.temperature = meshErrorState[10] self.partialTimestamp = Conversion.uint8_array_to_uint16(meshErrorState[11:13]) self.timestamp = reconstructTimestamp(time.time(), self.partialTimestamp) if self.crownstoneId == 0: self.deprecated = True
def parseOpCode5(serviceData, data): if len(data) == 18: if DeviceType.has_value(data[1]): serviceData.deviceType = DeviceType(data[1]) else: serviceData.deviceType = DeviceType.undefined serviceData.dataType = data[2] dataSlice = data[1:] if serviceData.dataType == 0: parseOpCode3_type0(serviceData, dataSlice) elif serviceData.dataType == 1: parseOpCode3_type1(serviceData, dataSlice) elif serviceData.dataType == 2: parseOpCode3_type2(serviceData, dataSlice) serviceData.rssiOfExternalCrownstone = Conversion.uint8_to_int8( dataSlice[15]) elif serviceData.dataType == 3: parseOpCode3_type3(serviceData, dataSlice) serviceData.rssiOfExternalCrownstone = Conversion.uint8_to_int8( dataSlice[15]) else: parseOpCode3_type0(serviceData, dataSlice)
def __init__(self, address, rssi, nameText, serviceData, serviceUUID=None): self.address = address self.rssi = rssi self.name = nameText self.serviceUUID = serviceUUID self.serviceData = None self.operationMode = None dataString = serviceData if serviceData is not None: if isinstance(serviceData, str): dataArray = Conversion.hex_string_to_uint8_array(dataString) self.serviceUUID = Conversion.uint8_array_to_uint16( [dataArray[0], dataArray[1]]) # pop the service UUID dataArray.pop(0) dataArray.pop(0) else: dataArray = serviceData if dataArray: self.serviceData = ServiceData(dataArray) self.operationMode = "NORMAL"
def obtainTimestamp(fullTimeStamp, lsb): timestampBytes = Conversion.uint32_to_uint8_array(int(fullTimeStamp)) lsbBytes = Conversion.uint16_to_uint8_array(lsb) restoredTimestamp = Conversion.uint8_array_to_uint32( [lsbBytes[0], lsbBytes[1], timestampBytes[2], timestampBytes[3]]) return restoredTimestamp
def getPacket(self): arr = [] arr += Conversion.uint16_to_uint8_array(self.type) arr += Conversion.uint16_to_uint8_array(self.length + 4) # the + 2 is for the stateType uint16 and +2 for the id arr += Conversion.uint16_to_uint8_array(self.stateType) arr += Conversion.uint16_to_uint8_array(self.id) arr += self.payload return arr
def getPacket(self): arr = [] arr.append(self.presenceType.value) arr += Conversion.uint64_to_uint8_array(self.getMask(self.locationIds)) arr += Conversion.uint32_to_uint8_array(self.delayInSeconds) return arr
def loadKeys(self, encryptionEnabled, adminKey, memberKey, guestKey, referenceId): self.encryptionEnabled = encryptionEnabled self.adminKey = Conversion.ascii_or_hex_string_to_16_byte_array(adminKey) self.memberKey = Conversion.ascii_or_hex_string_to_16_byte_array(memberKey) self.guestKey = Conversion.ascii_or_hex_string_to_16_byte_array(guestKey) self.referenceId = referenceId self.initializedKeys = True self.determineUserLevel()
def _verifyDecryption(decrypted, validationKey): # the conversion to uint32 only takes the first 4 bytes if Conversion.uint8_array_to_uint32(decrypted) == Conversion.uint8_array_to_uint32(validationKey): # remove checksum from decryption and return payload result = [0] * (len(decrypted) - SESSION_KEY_LENGTH) for i in range(0,len(result)): result[i] = decrypted[i+SESSION_KEY_LENGTH] return result else: raise BluenetBleException(BleError.ENCRYPTION_VALIDATION_FAILED, "Failed to validate result, Could not decrypt")
def __init__(self, payload): if len(payload) < self.packetSize: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.timestampCounter = Conversion.uint8_array_to_uint32(payload[0:4]) self.samples = [] for i in range(4, self.packetSize, self.sampleSize): self.samples.append( Conversion.uint8_array_to_int16(payload[i:i + self.sampleSize]))
def test_switchPacket(self): rawData = [0, 0, 1, 0, 100] sessionNonce = Conversion.string_to_uint8_array("12345") encryptionData = EncryptionHandler.encryptCTR( rawData, [128, 128, 128], sessionNonce, Conversion.string_to_uint8_array("AdminKeyOf16Byte")) self.assertEqual( encryptionData, bytes([ 171, 199, 94, 51, 230, 26, 253, 144, 182, 105, 56, 210, 94, 165, 184, 243 ]))
def parseOpCode3_type0(serviceData, data): if len(data) == 16: # dataType = data[0] serviceData.stateOfExternalCrownstone = False serviceData.crownstoneId = data[1] serviceData.switchState = data[2] serviceData.flagsBitmask = data[3] # bitmask states bitmaskArray = Conversion.uint8_to_bit_array(serviceData.flagsBitmask) serviceData.dimmerReady = bitmaskArray[0] serviceData.dimmingAllowed = bitmaskArray[1] serviceData.hasError = bitmaskArray[2] serviceData.switchLocked = bitmaskArray[3] serviceData.timeIsSet = bitmaskArray[4] serviceData.switchCraftEnabled = bitmaskArray[5] serviceData.tapToToggleEnabled = bitmaskArray[6] serviceData.behaviourOverridden = bitmaskArray[7] serviceData.temperature = Conversion.uint8_to_int8(data[4]) powerFactor = Conversion.uint8_to_int8(data[5]) realPower = Conversion.uint16_to_int16( Conversion.uint8_array_to_uint16([data[6], data[7]])) serviceData.powerFactor = float(powerFactor) / 127.0 # we cannot have a 0 for a power factor.To avoid division by 0, we set it to be either 0.01 or -0.01 if 0 <= serviceData.powerFactor < 0.01: serviceData.powerFactor = 0.01 elif -0.01 < serviceData.powerFactor < 0: serviceData.powerFactor = -0.01 serviceData.powerUsageReal = float(realPower) / 8.0 serviceData.powerUsageApparent = serviceData.powerUsageReal / serviceData.powerFactor serviceData.accumulatedEnergy = Conversion.uint32_to_int32( Conversion.uint8_array_to_uint32( [data[8], data[9], data[10], data[11]])) serviceData.partialTimestamp = Conversion.uint8_array_to_uint16( [data[12], data[13]]) serviceData.uniqueIdentifier = serviceData.partialTimestamp if serviceData.timeIsSet: serviceData.timestamp = reconstructTimestamp( time.time(), serviceData.partialTimestamp) else: serviceData.timestamp = serviceData.partialTimestamp # this is now a counter globalBitmaskArray = Conversion.uint8_to_bit_array(data[14]) serviceData.behaviourEnabled = globalBitmaskArray[0] serviceData.validation = data[15]
def parseState(self, meshStateItemState): self.crownstoneId = meshStateItemState[0] self.switchState = meshStateItemState[1] self.flagsBitmask = meshStateItemState[2] self.temperature = meshStateItemState[3] self.powerFactor = float(meshStateItemState[4]) / 127 self.powerUsageReal = float(Conversion.uint8_array_to_int16(meshStateItemState[5:7])) / 8 if self.powerFactor == 0: self.powerFactor = 1.0 self.powerUsageApparent = self.powerUsageReal / self.powerFactor self.accumulatedEnergy = Conversion.uint8_array_to_int32(meshStateItemState[7:11]) self.partialTimestamp = Conversion.uint8_array_to_uint16(meshStateItemState[11:13]) self.timestamp = reconstructTimestamp(time.time(), self.partialTimestamp) if self.crownstoneId == 0: self.deprecated = True
def getPacket(self): packet = [] packet += Conversion.uint16_to_uint8_array(self.type) packet += self.lengthAsUint8Array packet += self.payload return packet
def __init__(self, payload): self.stoneStates = [] if len(payload) != MESH_STATE_PACKET_SIZE: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.stoneStates = [] self.head = payload[0] self.tail = payload[1] self.size = payload[2] self.timestamp = Conversion.uint8_array_to_uint32(payload[4:8]) expectedSizeOfStoneStates = self.size * STONE_STATE_PACKET_SIZE if expectedSizeOfStoneStates + 8 > MESH_STATE_PACKET_SIZE: print("ERROR: CANT FIT STONE STATE PACKETS IN MESSAGE", expectedSizeOfStoneStates) return for i in range(0, self.size): self.stoneStates.append( StoneStatePacket(payload[8 + i * STONE_STATE_PACKET_SIZE:8 + (i + 1) * STONE_STATE_PACKET_SIZE])) # deprecation is when a stone id has multiple entrees in the data. Checking for this makes sure we only use the latest one. self._checkForDeprecation()
def getPacket(self): arr = [] arr.append(self.timeType.value) arr += Conversion.int32_to_uint8_array(self.offset) return arr
def getPacket(self): packet = [] packet.append(self.crownstoneId) packet.append(self.state) packet += Conversion.uint16_to_uint8_array(self.timeout) packet.append(self.intent) return packet
def getSetupPacket(crownstoneId, sphereId, adminKey, memberKey, basicKey, serviceDataKey, localizationKey, meshDeviceKey, meshAppKey, meshNetworkKey, ibeaconUUID, ibeaconMajor, ibeaconMinor): """ :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).getPacket()
def parseOpcode3_type3(serviceData, data): if len(data) == 17: parseOpcode3_type1(serviceData, data) # apply differences between type 1 and type 4 serviceData.stateOfExternalCrownstone = True serviceData.powerUsageReal = 0 serviceData.validation = Conversion.uint8_array_to_uint16( [data[15], data[16]])
def getUInt16Payload(self): if not self.valid: return 65535 if self.length >= 2: return Conversion.uint8_array_to_uint16( [self.payload[0], self.payload[1]]) else: return 65535
def getPacket(self): packet = [] packet.append(self.type) timeoutArray = Conversion.uint16_to_uint8_array(self.timeout) packet += timeoutArray packet.append(len(self.packets)) for keepAlivePacket in self.packets: packet += keepAlivePacket.getPacket() return packet
def parseOpCode5(serviceData, data): if len(data) == 16: serviceData.dataType = data[0] if serviceData.dataType == 0: parseOpCode3_type0(serviceData, data) elif serviceData.dataType == 1: parseOpCode3_type1(serviceData, data) elif serviceData.dataType == 2: parseOpCode3_type2(serviceData, data) serviceData.rssiOfExternalCrownstone = Conversion.uint8_to_int8( data[15]) elif serviceData.dataType == 3: parseOpCode3_type3(serviceData, data) serviceData.rssiOfExternalCrownstone = Conversion.uint8_to_int8( data[15]) else: parseOpCode3_type0(serviceData, data)
def __init__(self, action, state, timeout): packet = [] packet.append(action) packet.append(state) timeoutByteArray = Conversion.uint16_to_uint8_array(timeout) packet += timeoutByteArray super().__init__(ControlType.KEEP_ALIVE_STATE) self.loadByteArray(packet)
def __init__(self, payload, channelIndex): if len(payload) < self.packetSize: print("ERROR: INVALID PAYLOAD LENGTH", len(payload), payload) return self.channelIndex = channelIndex self.pin = payload[0] self.range = Conversion.uint8_array_to_uint32(payload[1:1+4]) self.refPin = payload[5]
def __init__(self, bitMask): self.bitMask = bitMask bitArray = Conversion.uint32_to_bit_array_reversed(bitMask) self.overCurrent = bitArray[31 - 0] self.overCurrentDimmer = bitArray[31 - 1] self.temperatureChip = bitArray[31 - 2] self.temperatureDimmer = bitArray[31 - 3] self.dimmerOnFailure = bitArray[31 - 4] self.dimmerOffFailure = bitArray[31 - 5]