import Foundation struct DeviceInfo { let receivedDate: Date /// The number of bytes recorded by the tracker let numberOfRecordedBytes: Int /// The number of measurements already performed let numberOfMeasurements: Int /// The interval between measurements (in seconds) let measurementInterval: Int /// The maximum number of bytes which can be requested let transferBlockSize: Int let deviceStartTime: Date let nextMeasurement: Date let sensor0: TemperatureSensor? let sensor1: TemperatureSensor? let storageSize: Int /** The number of seconds the device has been powered on */ var numberOfSecondsRunning: Int { Int(-deviceStartTime.timeIntervalSinceNow) } var storageFillRatio: Double { Double(numberOfRecordedBytes) / Double(storageSize) } var storageFillPercentage: Int { Int((storageFillRatio * 100).rounded()) } } extension DeviceInfo { static var size = 38 init?(info: Data) { guard info.count == DeviceInfo.size else { print("Invalid info size \(info.count)") return nil } let data = Array(info) self.receivedDate = Date() self.numberOfRecordedBytes = .init(high: data[1], low: data[0]) let secondsUntilNextMeasurement = UInt16(high: data[3], low: data[2]) self.nextMeasurement = Date().addingTimeInterval(Double(secondsUntilNextMeasurement)) self.measurementInterval = .init(high: data[5], low: data[4]) self.numberOfMeasurements = .init(high: data[7], low: data[6]) self.transferBlockSize = .init(high: data[9], low: data[8]) let secondsSincePowerOn = Int(uint32: data[13], data[12], data[11], data[10]) self.deviceStartTime = Date().addingTimeInterval(Double(-secondsSincePowerOn)) self.sensor0 = .init(address: Array(data[16..<24]), valueByte: data[14], secondsAgo: UInt16(high: data[33], low: data[32])) self.sensor1 = .init(address: Array(data[24..<32]), valueByte: data[15], secondsAgo: UInt16(high: data[35], low: data[34])) self.storageSize = .init(high: data[37], low: data[36]) } } private extension UInt16 { init(high: UInt8, low: UInt8) { self = UInt16(high) << 8 + UInt16(low) } } private extension Int { init(uint32 byte0: UInt8, _ byte1: UInt8, _ byte2: UInt8, _ byte3: UInt8) { self = (Int(byte0) << 24) | (Int(byte1) << 16) | (Int(byte2) << 8) | Int(byte3) } init(high: UInt8, low: UInt8) { self = Int(high) << 8 + Int(low) } } extension DeviceInfo { static var mock: DeviceInfo { .init( receivedDate: Date(), numberOfRecordedBytes: 123, numberOfMeasurements: 234, measurementInterval: 60, transferBlockSize: 180, deviceStartTime: .now.addingTimeInterval(-1000), nextMeasurement: .now.addingTimeInterval(5), sensor0: .init(address: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], value: .value(21.0), date: .now.addingTimeInterval(-2)), sensor1: .init(address: [0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09], value: .value(19.0), date: .now.addingTimeInterval(-4)), storageSize: 10000) } }