diff --git a/Bluetooth/LibreTransmitterMetadata.swift b/Bluetooth/LibreTransmitterMetadata.swift index 9f5c836..dfe50db 100644 --- a/Bluetooth/LibreTransmitterMetadata.swift +++ b/Bluetooth/LibreTransmitterMetadata.swift @@ -110,7 +110,7 @@ public enum SensorType: String, CustomStringConvertible { case 0xDF, 0xA2: self = .libre1 case 0xE5, 0xE6: self = .libreUS14day case 0x70: self = .libreProH - case 0xC5, 0x9D, 0xC6: self = .libre2 + case 0xC5, 0x9D, 0xC6, 0x7F: self = .libre2 case 0x76: self = patchInfo[3] == 0x02 ? .libre2US : patchInfo[3] == 0x04 ? .libre2CA : patchInfo[2] >> 4 == 7 ? .libreSense : .unknown default: if patchInfo.count == 24 { diff --git a/Bluetooth/Transmitter/Libre2DirectTransmitter.swift b/Bluetooth/Transmitter/Libre2DirectTransmitter.swift index f57e63a..666a049 100644 --- a/Bluetooth/Transmitter/Libre2DirectTransmitter.swift +++ b/Bluetooth/Transmitter/Libre2DirectTransmitter.swift @@ -46,7 +46,27 @@ class Libre2DirectTransmitter: LibreTransmitterProxyProtocol { private var metadata: LibreTransmitterMetadata? class func canSupportPeripheral(_ peripheral: PeripheralProtocol) -> Bool { - peripheral.name?.lowercased().starts(with: "abbott") ?? false + // name can be one of the following formats: + // : example + //ABBOT: ABBOTT3MH015PCNC4 + // : A4B7C9023F8D + + guard let name = peripheral.name else { + return false + } + + if name.lowercased().starts(with: "abbott") == true { + print("Libre 2 detected using legacy name format as matcher") + return true + } + + print("Libre 2 detection using MAC address as matcher: \(UserDefaults.standard.preSelectedSensor?.macAddress?.lowercased()) vs \(name.lowercased())") + if let sensor = UserDefaults.standard.preSelectedSensor, let macAddress = sensor.macAddress { + return name.lowercased().contains(macAddress.lowercased()) + } + + + return false } class func getDeviceDetailsFromAdvertisement(advertisementData: [String: Any]?) -> String? { @@ -143,7 +163,7 @@ class Libre2DirectTransmitter: LibreTransmitterProxyProtocol { metadata = LibreTransmitterMetadata(hardware: nil, firmware: nil, battery: 100, name: Self.shortTransmitterName, - macAddress: nil, + macAddress: sensor.macAddress, patchInfo: sensor.patchInfo, uid: [UInt8](sensor.uuid)) diff --git a/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift b/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift index 7b30801..7a28039 100644 --- a/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift +++ b/Bluetooth/Transmitter/LibreTransmitterProxyManager.swift @@ -448,6 +448,7 @@ public final class LibreTransmitterProxyManager: NSObject, CBCentralManagerDeleg } } + private func verifyLibre2ManufacturerData(peripheral: CBPeripheral, selectedUid: Data ,advertisementData: [String: Any]) -> Bool { guard let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data else { logger.debug("manufacturerData was not retrieved") @@ -488,9 +489,23 @@ public final class LibreTransmitterProxyManager: NSObject, CBCentralManagerDeleg let sensor = UserDefaults.standard.preSelectedSensor logger.debug("preselected sensor is: \(String(describing:sensor))") + var verified = false + + // Starting in mid 2025, libre2 plus sensors in europe identify them self with + // their mac address in the device name + if let peripheralName = peripheral.name, let preselectedMac = sensor?.macAddress { + verified = peripheralName == preselectedMac + logger.debug("Verifiying libre2 connection using mac address method:. \(verified)") + } + + if !verified { + verified = verifyLibre2ManufacturerData(peripheral: peripheral, selectedUid: selectedUid, advertisementData: advertisementData) + logger.debug("Verifiying libre2 connection using legacy manufacturerData method: \(verified)") + + } - if !verifyLibre2ManufacturerData(peripheral: peripheral, selectedUid: selectedUid, advertisementData: advertisementData) { - logger.debug("failed Verifiying libre2 connection using manufacturerData") + if !verified { + logger.debug("verification failed, not connecting") return } diff --git a/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift b/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift index 4bcf343..82953a0 100644 --- a/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift +++ b/Bluetooth/Transmitter/LibreTransmitterProxyProtocol.swift @@ -37,7 +37,8 @@ public protocol LibreTransmitterProxyProtocol: AnyObject { extension LibreTransmitterProxyProtocol { func canSupportPeripheral(_ peripheral: PeripheralProtocol) -> Bool { - Self.canSupportPeripheral(peripheral) + print("canSupportPeripheral called") + return Self.canSupportPeripheral(peripheral) } public var staticType: LibreTransmitterProxyProtocol.Type { Self.self diff --git a/LibreSensor/SensorContents/Sensor.swift b/LibreSensor/SensorContents/Sensor.swift index e947655..58e7651 100644 --- a/LibreSensor/SensorContents/Sensor.swift +++ b/LibreSensor/SensorContents/Sensor.swift @@ -80,66 +80,23 @@ public struct CalibrationToSensorMapping: Codable { public struct Sensor: Codable { public let uuid: Data public let patchInfo: Data - // public let calibrationInfo: SensorData.CalibrationInfo - // public let family: SensorFamily - // public let type: SensorType - // public let region: SensorRegion - // public let serial: String? - // public var state: SensorState public var age: Int? public var maxAge: Int - // public var lifetime: Int public var unlockCount: Int var sensorName : String? + var macAddress : String? - /* - public var unlockCount: Int { - get { - return UserDefaults.standard.integer(forKey: Key.sensorUnlockCount.rawValue) - } - set { - UserDefaults.standard.setValue(newValue, forKey: Key.sensorUnlockCount.rawValue) - } - }*/ - - /* - public var elapsedLifetime: Int? { - get { - if let remainingLifetime { - return max(0, lifetime - remainingLifetime) - } - - return nil - } - } - - public var remainingLifetime: Int? { - get { - if let age { - return max(0, lifetime - age) - } - - return nil - } - } */ - - public init(uuid: Data, patchInfo: Data, maxAge: Int, unlockCount: Int = 0, sensorName: String? = nil) { + public init(uuid: Data, patchInfo: Data, maxAge: Int, unlockCount: Int = 0, sensorName: String? = nil, macAddress: String? = nil) { self.uuid = uuid self.patchInfo = patchInfo - - // self.family = SensorFamily(patchInfo: patchInfo) - // self.type = SensorType(patchInfo: patchInfo) - // self.region = SensorRegion(patchInfo: patchInfo) - // self.serial = sensorSerialNumber(sensorUID: self.uuid, sensorFamily: self.family) - // self.state = SensorState(fram: fram) - // self.lifetime = Int(fram[327]) << 8 + Int(fram[326]) self.unlockCount = 0 self.maxAge = maxAge // self.calibrationInfo = calibrationInfo self.sensorName = sensorName + self.macAddress = macAddress } public var description: String { diff --git a/LibreSensor/SensorPairing/SensorPairing.swift b/LibreSensor/SensorPairing/SensorPairing.swift index a495065..fc864f8 100644 --- a/LibreSensor/SensorPairing/SensorPairing.swift +++ b/LibreSensor/SensorPairing/SensorPairing.swift @@ -15,9 +15,10 @@ public class SensorPairingInfo: ObservableObject, Codable { @Published public var streamingEnabled: Bool @Published public var sensorName : String? = nil + @Published public var macAddress : String? = nil enum CodingKeys: CodingKey { - case uuid, patchInfo, fram, streamingEnabled, sensorName + case uuid, patchInfo, fram, streamingEnabled, sensorName, macAddress } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) @@ -27,6 +28,7 @@ public class SensorPairingInfo: ObservableObject, Codable { try container.encode(fram, forKey: .fram) try container.encode(streamingEnabled, forKey: .streamingEnabled) try container.encode(sensorName, forKey: .sensorName) + try container.encode(macAddress, forKey: .macAddress) } @@ -39,15 +41,17 @@ public class SensorPairingInfo: ObservableObject, Codable { fram = try container.decode(Data.self, forKey: .fram) streamingEnabled = try container.decode(Bool.self, forKey: .streamingEnabled) sensorName = try container.decode(String?.self, forKey: .sensorName) + macAddress = try container.decode(String?.self, forKey: .macAddress) } - public init(uuid: Data=Data(), patchInfo: Data=Data(), fram: Data=Data(), streamingEnabled: Bool = false, sensorName: String? = nil ) { + public init(uuid: Data=Data(), patchInfo: Data=Data(), fram: Data=Data(), streamingEnabled: Bool = false, sensorName: String? = nil, macAddress: String? = nil ) { self.uuid = uuid self.patchInfo = patchInfo self.fram = fram self.streamingEnabled = streamingEnabled self.sensorName = sensorName + self.macAddress = macAddress } public var sensorData: SensorData? { diff --git a/LibreSensor/SensorPairing/SensorPairingService.swift b/LibreSensor/SensorPairing/SensorPairingService.swift index 492d64c..ce31cd4 100644 --- a/LibreSensor/SensorPairing/SensorPairingService.swift +++ b/LibreSensor/SensorPairing/SensorPairingService.swift @@ -169,9 +169,11 @@ public class SensorPairingService: NSObject, NFCTagReaderSessionDelegate, Sensor tag.customCommand(requestFlags: .highDataRate, customCommandCode: Int(cmd.code), customRequestParameters: cmd.parameters) { response, _ in var streamingEnabled = false + var macAddress : String? if subCmd == .enableStreaming && response.count == 6 { streamingEnabled = true + macAddress = Data(response.reversed()).hexEncodedString().uppercased() } @@ -179,7 +181,7 @@ public class SensorPairingService: NSObject, NFCTagReaderSessionDelegate, Sensor let patchHex = patchInfo.hexEncodedString() let sensorType = SensorType(patchInfo: patchInfo) - print("got patchhex: \(patchHex) and sensorType: \(sensorType)") + print("got patchhex: \(patchHex) and sensorType: \(sensorType), with mac address: \(macAddress)") guard sensorUID.count == 8 && patchInfo.count == 6 && fram.count == 344 else { // self.readingsSubject.send(completion: .failure(LibreError.noSensorData)) @@ -199,7 +201,7 @@ public class SensorPairingService: NSObject, NFCTagReaderSessionDelegate, Sensor do { let decryptedBytes = try Libre2.decryptFRAM(type: sensorType, id: [UInt8](sensorUID), info: patchInfo, data: [UInt8](fram)) - self.sendUpdate(SensorPairingInfo(uuid: sensorUID, patchInfo: patchInfo, fram: Data(decryptedBytes), streamingEnabled: streamingEnabled)) + self.sendUpdate(SensorPairingInfo(uuid: sensorUID, patchInfo: patchInfo, fram: Data(decryptedBytes), streamingEnabled: streamingEnabled, macAddress: macAddress)) session.invalidate() return } catch { diff --git a/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift b/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift index 8983ae1..cdf4303 100644 --- a/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift +++ b/LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift @@ -73,7 +73,7 @@ struct Libre2DirectSetup: View { let max = info.sensorData?.maxMinutesWearTime ?? 0 - let sensor = Sensor(uuid: info.uuid, patchInfo: info.patchInfo, maxAge: max, sensorName: info.sensorName) + let sensor = Sensor(uuid: info.uuid, patchInfo: info.patchInfo, maxAge: max, sensorName: info.sensorName, macAddress: info.macAddress) UserDefaults.standard.preSelectedSensor = sensor SelectionState.shared.selectedUID = pairingInfo.uuid