From c3c9ba23e1e79323fd30ee69d10cb943772e5f45 Mon Sep 17 00:00:00 2001 From: Paul Plant <37302780+paulplant@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:28:34 +0200 Subject: [PATCH 1/2] limit/move G7 type expiry check Also, prevent TreatmentTableViewCell crash during development - this is only needed if coredata has some new treatment types from dev work that are then no longer present if the instance is overwritten with an earlier version of the app. Nothing related to Stelo but might as well fix it. Enum switches should *always* have a default conditional for this reason! --- .../CGM/Dexcom/G7/CGMG7Transmitter.swift | 41 +++++++++++-------- .../CGM/Generic/CGMTransmitter.swift | 4 +- .../RootViewController.swift | 7 +--- .../Treatments/TreatmentTableViewCell.swift | 6 +++ 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/xdrip/BluetoothTransmitter/CGM/Dexcom/G7/CGMG7Transmitter.swift b/xdrip/BluetoothTransmitter/CGM/Dexcom/G7/CGMG7Transmitter.swift index c0c1c9e04..b67f5a98a 100644 --- a/xdrip/BluetoothTransmitter/CGM/Dexcom/G7/CGMG7Transmitter.swift +++ b/xdrip/BluetoothTransmitter/CGM/Dexcom/G7/CGMG7Transmitter.swift @@ -210,25 +210,29 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter { return } - var maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDays - - // check if it's a Stelo and if so, update the maxSensorAge - if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId, transmitterIdString.startsWith("DX01") { - maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDaysStelo - } - let sensorAgeInDays = Double(round((g7GlucoseMessage.sensorAge / 3600 / 24) * 10) / 10) - // G7/ONE+/Stelo has the peculiarity that it will keep sending/repeating the same BG value (without ever changing) via BLE even after the session officially ends. - // to avoid this, let's check if the sensor is still within maxSensorAge before we continue - guard sensorAgeInDays < maxSensorAgeInDays else { - trace(" G7 is expired so will not process reading. sensorAge: %{public}@ / maxSensorAgeInDays: %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .error, sensorAgeInDays.description, maxSensorAgeInDays.description) - return + var maxSensorAgeInDays: Double = 0.0 + + // check if we already have the transmitterId (or device name). If so, set the maxSensorAge and then perform a quick check to see if the sensor hasn't expired. + if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId { + if transmitterIdString.startsWith("DX01") { + maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDaysStelo + } else { + maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDays + } + + // G7/ONE+/Stelo has the peculiarity that it will keep sending/repeating the same BG value (without ever changing) via BLE even after the session officially ends. + // to avoid this, let's check if the sensor is still within maxSensorAge before we continue + if sensorAgeInDays > maxSensorAgeInDays { + trace(" %{public}@ is expired so will not process reading. sensorAge: %{public}@ / maxSensorAgeInDays: %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .error, UserDefaults.standard.activeSensorTransmitterId ?? "sensor", sensorAgeInDays.description, maxSensorAgeInDays.description) + return + } } trace(" received g7GlucoseMessage mesage, calculatedValue = %{public}@, timeStamp = %{public}@, sensorAge = %{public}@ / %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .info, g7GlucoseMessage.calculatedValue.description, g7GlucoseMessage.timeStamp.description(with: .current)) - trace(" received g7GlucoseMessage mesage, sensorAge = %{public}@ / %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .info, sensorAgeInDays.description, maxSensorAgeInDays.description) + trace(" received g7GlucoseMessage mesage, sensorAge = %{public}@ / %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .info, sensorAgeInDays.description, maxSensorAgeInDays > 0 ? maxSensorAgeInDays.description : "waiting...") sensorAge = g7GlucoseMessage.sensorAge @@ -376,10 +380,15 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter { func maxSensorAgeInDays() -> Double? { - if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId, transmitterIdString.startsWith("DX01") { - return ConstantsDexcomG7.maxSensorAgeInDaysStelo + if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId { + if transmitterIdString.startsWith("DX01") { + return ConstantsDexcomG7.maxSensorAgeInDaysStelo + } else { + return ConstantsDexcomG7.maxSensorAgeInDays + } } else { - return ConstantsDexcomG7.maxSensorAgeInDays + // if we haven't yet established the activeSensorTransmitterId (or device name) then return 0 - RVC will use this to know that we're still waiting + return 0 } } diff --git a/xdrip/BluetoothTransmitter/CGM/Generic/CGMTransmitter.swift b/xdrip/BluetoothTransmitter/CGM/Generic/CGMTransmitter.swift index 13d7f7b58..d5298f4e5 100644 --- a/xdrip/BluetoothTransmitter/CGM/Generic/CGMTransmitter.swift +++ b/xdrip/BluetoothTransmitter/CGM/Generic/CGMTransmitter.swift @@ -316,9 +316,11 @@ enum CGMTransmitterType:String, CaseIterable { return "Dexcom Stelo" } else if transmitterIdString.startsWith("DX02") { return "Dexcom ONE+" + } else { + return "Dexcom G7" } } - return "Dexcom G7" + return "Dexcom - please wait..." case .Libre2: if let activeSensorMaxSensorAgeInDays = UserDefaults.standard.activeSensorMaxSensorAgeInDays, activeSensorMaxSensorAgeInDays >= 15 { diff --git a/xdrip/View Controllers/Root View Controller/RootViewController.swift b/xdrip/View Controllers/Root View Controller/RootViewController.swift index 016da0869..317aee22e 100644 --- a/xdrip/View Controllers/Root View Controller/RootViewController.swift +++ b/xdrip/View Controllers/Root View Controller/RootViewController.swift @@ -3102,16 +3102,11 @@ final class RootViewController: UIViewController, ObservableObject { // check if there is a transmitter connected (needed as Dexcom will only connect briefly every 5 minutes) // if there is a transmitter connected, pull the current maxSensorAgeInDays and store in in UserDefaults if let cgmTransmitter = self.bluetoothPeripheralManager?.getCGMTransmitter(), let maxDays = cgmTransmitter.maxSensorAgeInDays() { - - if maxDays > 0 { - UserDefaults.standard.activeSensorMaxSensorAgeInDays = maxDays - } - + UserDefaults.standard.activeSensorMaxSensorAgeInDays = maxDays UserDefaults.standard.activeSensorDescription = cgmTransmitter.cgmTransmitterType().detailedDescription() // update the sensor type - needed to make sure we test with the correct warm-up times later sensorType = cgmTransmitter.cgmTransmitterType().sensorType() - } // let's just check that we've got enough information to display the view diff --git a/xdrip/View Controllers/Treatments/TreatmentTableViewCell.swift b/xdrip/View Controllers/Treatments/TreatmentTableViewCell.swift index 8cbb0c13f..dc2c88af6 100644 --- a/xdrip/View Controllers/Treatments/TreatmentTableViewCell.swift +++ b/xdrip/View Controllers/Treatments/TreatmentTableViewCell.swift @@ -40,6 +40,9 @@ class TreatmentTableViewCell: UITableViewCell { case .BgCheck: self.iconImageView.tintColor = ConstantsGlucoseChart.bgCheckTreatmentColorInner + default: + self.iconImageView.tintColor = nil + } switch treatment.treatmentType { @@ -56,6 +59,9 @@ class TreatmentTableViewCell: UITableViewCell { case .BgCheck: self.iconImageView.image = UIImage(systemName: "drop.fill") ?? nil + default: + self.iconImageView.tintColor = nil + } // treatment type label From f1377ceee48f2a6e6a1c0142dfa2af8947b1966c Mon Sep 17 00:00:00 2001 From: Paul Plant <37302780+paulplant@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:31:11 +0200 Subject: [PATCH 2/2] updates to logging --- .../ContactImage/ContactImageManager.swift | 16 +++++++---- xdrip/Utilities/Trace.swift | 28 +++++++++++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/xdrip/Managers/ContactImage/ContactImageManager.swift b/xdrip/Managers/ContactImage/ContactImageManager.swift index 0d32400c8..0d3c9829b 100644 --- a/xdrip/Managers/ContactImage/ContactImageManager.swift +++ b/xdrip/Managers/ContactImage/ContactImageManager.swift @@ -81,9 +81,12 @@ class ContactImageManager: NSObject { // check that access to contacts is authorized by the user guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else { - trace("in updateContact, access to contacts is not authorized, setting enableContactImage to false", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info) - - UserDefaults.standard.enableContactImage = false + // if it isn't, and the user has enabled the feature, then disable it + if UserDefaults.standard.enableContactImage { + trace("in updateContact, access to contacts is not authorized so setting enableContactImage to false", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info) + + UserDefaults.standard.enableContactImage = false + } return } @@ -124,7 +127,10 @@ class ContactImageManager: NSObject { // we'll search for all results and then just use the first one for now // we do it this way so that in the future we want to add a descriptor to the family name to have various contact images (such as "BG", "IOB", "COB" as needed) if let contacts = try? self.contactStore.unifiedContacts(matching: predicate, keysToFetch: keyToFetch), let contact = contacts.first { - trace("in updateContact, existing contact found. Updating it's contact image.", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info) + + if lastReading.count > 0 { + trace("in updateContact, '%{public}@' contact found. Updating the contact image to %{public}@ %{public}@.", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info, ConstantsHomeView.applicationName, lastReading[0].calculatedValue.mgDlToMmolAndToString(mgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl), UserDefaults.standard.bloodGlucoseUnitIsMgDl ? Texts_Common.mgdl : Texts_Common.mmol) + } // create a mutableContact from the existing contact so that we can modify it guard let mutableContact = contact.mutableCopy() as? CNMutableContact else { return } @@ -135,7 +141,7 @@ class ContactImageManager: NSObject { // we'll update the existing contact with the new data saveRequest.update(mutableContact) } else { - trace("in updateContact, no existing contact found. Creating a new contact called '%{public}@' and adding a contact image.", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info, ConstantsHomeView.applicationName) + trace("in updateContact, no existing contact found. Creating a new contact called '%{public}@' and adding a contact image with %{public}@ %{public}@.", log: self.log, category: ConstantsLog.categoryContactImageManager, type: .info, ConstantsHomeView.applicationName, lastReading[0].calculatedValue.mgDlToMmolAndToString(mgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl), UserDefaults.standard.bloodGlucoseUnitIsMgDl ? Texts_Common.mgdl : Texts_Common.mmol) // create a new mutable contact instance and assign properties to it let contact = CNMutableContact() diff --git a/xdrip/Utilities/Trace.swift b/xdrip/Utilities/Trace.swift index 22708eeba..18102af9b 100644 --- a/xdrip/Utilities/Trace.swift +++ b/xdrip/Utilities/Trace.swift @@ -366,9 +366,9 @@ class Trace { traceInfo.appendStringAndNewLine("\nNotifications settings:") traceInfo.appendStringAndNewLine(" Show BG in notifications: " + UserDefaults.standard.showReadingInNotification.description) traceInfo.appendStringAndNewLine(" Notification interval: " + UserDefaults.standard.notificationInterval.description + " minutes") - traceInfo.appendStringAndNewLine(" Live Activities Type: " + UserDefaults.standard.liveActivityType.debugDescription) + traceInfo.appendStringAndNewLine(" Live Activity type: " + UserDefaults.standard.liveActivityType.debugDescription) traceInfo.appendStringAndNewLine(" Show BG in app badge: " + UserDefaults.standard.showReadingInAppBadge.description) - traceInfo.appendStringAndNewLine(" Multiply app badge by 10: " + (UserDefaults.standard.bloodGlucoseUnitIsMgDl ? "-" : UserDefaults.standard.multipleAppBadgeValueWith10.description)) + traceInfo.appendStringAndNewLine(" Multiply app badge by 10: " + (UserDefaults.standard.bloodGlucoseUnitIsMgDl ? "\(UserDefaults.standard.multipleAppBadgeValueWith10.description) (but not used in mg/dL)" : UserDefaults.standard.multipleAppBadgeValueWith10.description)) traceInfo.appendStringAndNewLine("\nHome screen settings:") traceInfo.appendStringAndNewLine(" Allow chart rotation: " + UserDefaults.standard.allowScreenRotation.description) @@ -379,6 +379,8 @@ class Trace { traceInfo.appendStringAndNewLine(" Target: " + UserDefaults.standard.targetMarkValueInUserChosenUnitRounded.description) traceInfo.appendStringAndNewLine(" Low: " + UserDefaults.standard.lowMarkValueInUserChosenUnitRounded.description) traceInfo.appendStringAndNewLine(" Urgent low: " + UserDefaults.standard.urgentLowMarkValueInUserChosenUnitRounded.description) + traceInfo.appendStringAndNewLine(" Hours to show on main chart: " + UserDefaults.standard.chartWidthInHours.description) + traceInfo.appendStringAndNewLine(" Hours to show on mini-chart: " + UserDefaults.standard.miniChartHoursToShow.description) traceInfo.appendStringAndNewLine("\nTreatments settings:") traceInfo.appendStringAndNewLine(" Show treatments: " + UserDefaults.standard.showTreatmentsOnChart.description) @@ -388,6 +390,7 @@ class Trace { traceInfo.appendStringAndNewLine("\nStatistics settings:") traceInfo.appendStringAndNewLine(" Show statistics: " + UserDefaults.standard.showStatistics.description) + traceInfo.appendStringAndNewLine(" Statistics days: " + UserDefaults.standard.daysToUseStatistics.description) traceInfo.appendStringAndNewLine(" Time in Range type: " + UserDefaults.standard.timeInRangeType.description) traceInfo.appendStringAndNewLine(" Show HbA1c in mmols/mol: " + UserDefaults.standard.useIFCCA1C.description) @@ -397,11 +400,7 @@ class Trace { traceInfo.appendStringAndNewLine(" URL: " + ((UserDefaults.standard.nightscoutUrl?.description ?? "") != "" ? "present" : "missing")) traceInfo.appendStringAndNewLine(" API_SECRET: " + ((UserDefaults.standard.nightscoutAPIKey?.description ?? "") != "" ? "present" : "missing")) traceInfo.appendStringAndNewLine(" Token: " + ((UserDefaults.standard.nightscoutToken?.description ?? "") != "" ? "present" : "missing")) - if UserDefaults.standard.nightscoutPort != 0 { - traceInfo.appendStringAndNewLine(" Port: " + UserDefaults.standard.nightscoutPort.description) - } else { - traceInfo.appendStringAndNewLine(" Port: Missing") - } + traceInfo.appendStringAndNewLine(" Port: " + ((UserDefaults.standard.nightscoutPort != 0) ? UserDefaults.standard.nightscoutPort.description : " missing")) } traceInfo.appendStringAndNewLine("\nDexcom Share settings:") @@ -450,8 +449,9 @@ class Trace { } traceInfo.appendStringAndNewLine("\nContact Image settings:") - traceInfo.appendStringAndNewLine(" Create contact: " + UserDefaults.standard.enableContactImage.description) + traceInfo.appendStringAndNewLine(" Enable contact image: " + UserDefaults.standard.enableContactImage.description) traceInfo.appendStringAndNewLine(" Show trend: " + UserDefaults.standard.displayTrendInContactImage.description) + traceInfo.appendStringAndNewLine(" Use high contrast: " + UserDefaults.standard.useHighContrastContactImage.description) traceInfo.appendStringAndNewLine("\nData management settings:") traceInfo.appendStringAndNewLine(" Retention period: " + UserDefaults.standard.retentionPeriodInDays.description + " days") @@ -461,11 +461,14 @@ class Trace { traceInfo.appendStringAndNewLine(" Show developer settings: " + UserDefaults.standard.showDeveloperSettings.description) traceInfo.appendStringAndNewLine(" NS log enabled: " + UserDefaults.standard.NSLogEnabled.description) traceInfo.appendStringAndNewLine(" OS log enabled: " + UserDefaults.standard.OSLogEnabled.description) - traceInfo.appendStringAndNewLine(" Smooth Libre readings: " + UserDefaults.standard.smoothLibreValues.description) traceInfo.appendStringAndNewLine(" Suppress unlock payload: " + UserDefaults.standard.suppressUnLockPayLoad.description) traceInfo.appendStringAndNewLine(" OS-AID share type: " + UserDefaults.standard.loopShareType.description) traceInfo.appendStringAndNewLine(" LibreLinkUp version: " + (UserDefaults.standard.libreLinkUpVersion?.description ?? "nil")) + // misc settings + traceInfo.appendStringAndNewLine("\nMisc settings:") + traceInfo.appendStringAndNewLine(" Use debug level logs: " + UserDefaults.standard.addDebugLevelLogsInTraceFileAndNSLog.description) + traceInfo.appendStringAndNewLine(paragraphSeperator) traceInfo.appendStringAndNewLine("General flags/variables:\n") @@ -485,7 +488,7 @@ class Trace { } else { traceInfo.appendStringAndNewLine(" Sensor start date: nil") } - traceInfo.appendStringAndNewLine(" Sensor max days: " + (Int(UserDefaults.standard.activeSensorMaxSensorAgeInDays ?? 0)).description) + traceInfo.appendStringAndNewLine(" Sensor max days: " + (UserDefaults.standard.activeSensorMaxSensorAgeInDays ?? 0).description) traceInfo.appendStringAndNewLine(" Transmitter ID: " + (UserDefaults.standard.activeSensorTransmitterId?.description ?? "nil")) } else { traceInfo.appendStringAndNewLine(" Not used in Nightscout follower mode") @@ -504,10 +507,10 @@ class Trace { let alertTypesAccessor = AlertTypesAccessor(coreDataManager: coreDataManager) // all bluetooth transmitters - traceInfo.appendStringAndNewLine("List of Bluetooth Peripherals:\n") + traceInfo.appendStringAndNewLine("List of Bluetooth Peripherals:") for blePeripheral in bLEPeripheralAccessor.getBLEPeripherals() { - traceInfo.appendStringAndNewLine(" Name: " + blePeripheral.name) + traceInfo.appendStringAndNewLine("\n Name: " + blePeripheral.name) traceInfo.appendStringAndNewLine(" Address: " + blePeripheral.address) if let alias = blePeripheral.alias { traceInfo.appendStringAndNewLine(" Alias: " + alias) @@ -642,6 +645,7 @@ class Trace { if blePeripheral.libre2 != nil { traceInfo.appendStringAndNewLine(" Type: " + bluetoothPeripheralType.rawValue) + traceInfo.appendStringAndNewLine(" Smooth Libre readings: " + UserDefaults.standard.smoothLibreValues.description) }