Просмотр исходного кода

Adding iage, including some debug prints

Jonas Björkert 2 лет назад
Родитель
Сommit
d4437926ee

+ 8 - 0
LoopFollow.xcodeproj/project.pbxproj

@@ -33,6 +33,8 @@
 		DD493AE52ACF2383009A6922 /* Treatments.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE42ACF2383009A6922 /* Treatments.swift */; };
 		DD493AE72ACF23CF009A6922 /* DeviceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE62ACF23CF009A6922 /* DeviceStatus.swift */; };
 		DD493AE92ACF2445009A6922 /* BGData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE82ACF2445009A6922 /* BGData.swift */; };
+		DD5334212C60EBEE00062F9D /* InsulinCartridgeChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5334202C60EBEE00062F9D /* InsulinCartridgeChange.swift */; };
+		DD5334232C60ED3600062F9D /* IAge.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5334222C60ED3600062F9D /* IAge.swift */; };
 		DD608A082C1F584900F91132 /* DeviceStatusLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A072C1F584900F91132 /* DeviceStatusLoop.swift */; };
 		DD608A0A2C23593900F91132 /* SMB.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A092C23593900F91132 /* SMB.swift */; };
 		DD608A0C2C27415C00F91132 /* BackgroundAlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A0B2C27415C00F91132 /* BackgroundAlertManager.swift */; };
@@ -250,6 +252,8 @@
 		DD493AE42ACF2383009A6922 /* Treatments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Treatments.swift; sourceTree = "<group>"; };
 		DD493AE62ACF23CF009A6922 /* DeviceStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatus.swift; sourceTree = "<group>"; };
 		DD493AE82ACF2445009A6922 /* BGData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGData.swift; sourceTree = "<group>"; };
+		DD5334202C60EBEE00062F9D /* InsulinCartridgeChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinCartridgeChange.swift; sourceTree = "<group>"; };
+		DD5334222C60ED3600062F9D /* IAge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAge.swift; sourceTree = "<group>"; };
 		DD608A072C1F584900F91132 /* DeviceStatusLoop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatusLoop.swift; sourceTree = "<group>"; };
 		DD608A092C23593900F91132 /* SMB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMB.swift; sourceTree = "<group>"; };
 		DD608A0B2C27415C00F91132 /* BackgroundAlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundAlertManager.swift; sourceTree = "<group>"; };
@@ -524,6 +528,7 @@
 				DDF9676D2AD08C6E00C5EB95 /* SiteChange.swift */,
 				DD608A092C23593900F91132 /* SMB.swift */,
 				DDD10F0A2C54192A00D76A8E /* TemporaryTarget.swift */,
+				DD5334202C60EBEE00062F9D /* InsulinCartridgeChange.swift */,
 			);
 			path = Treatments;
 			sourceTree = "<group>";
@@ -542,6 +547,7 @@
 				DD608A072C1F584900F91132 /* DeviceStatusLoop.swift */,
 				DD0C0C5F2C415B9D00DBADDF /* ProfileManager.swift */,
 				DD0C0C612C4175FD00DBADDF /* NSProfile.swift */,
+				DD5334222C60ED3600062F9D /* IAge.swift */,
 			);
 			path = Nightscout;
 			sourceTree = "<group>";
@@ -1105,6 +1111,7 @@
 				FCC6886724898F8000A0279D /* UserDefaultsValue.swift in Sources */,
 				DDF699942C555B310058A8D9 /* ViewControllerManager.swift in Sources */,
 				DDCF979E24C2382A002C9752 /* AppStateController.swift in Sources */,
+				DD5334212C60EBEE00062F9D /* InsulinCartridgeChange.swift in Sources */,
 				FC97881E2485969B00A7906C /* NightScoutViewController.swift in Sources */,
 				DD608A0A2C23593900F91132 /* SMB.swift in Sources */,
 				DDCF979824C1489C002C9752 /* GraphSettingsViewController.swift in Sources */,
@@ -1176,6 +1183,7 @@
 				DDD10F052C529DA200D76A8E /* ObservableValue.swift in Sources */,
 				FC1BDD2D24A23204001B652C /* StatsView.swift in Sources */,
 				FCE537BC249A4D7D00F80BF8 /* carbBolusArrays.swift in Sources */,
+				DD5334232C60ED3600062F9D /* IAge.swift in Sources */,
 				FCD2A27D24C9D044009F7B7B /* Globals.swift in Sources */,
 				DD0C0C642C45A59400DBADDF /* HKUnit+Extensions.swift in Sources */,
 				DDCF979A24C14DB4002C9752 /* WatchSettingsViewController.swift in Sources */,

+ 4 - 0
LoopFollow/Controllers/NightScout.swift

@@ -19,6 +19,10 @@ extension MainViewController {
         var created_at: String
     }
 
+    struct iageData: Codable {
+        var created_at: String
+    }
+
     //NS Basal Profile Struct
     struct basalProfileStruct: Codable {
         var value: Double

+ 65 - 0
LoopFollow/Controllers/Nightscout/IAge.swift

@@ -0,0 +1,65 @@
+//
+//  IAge.swift
+//  LoopFollow
+//
+//  Created by Jonas Björkert on 2024-08-05.
+//  Copyright © 2024 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+extension MainViewController {
+    // NS Iage Web Call
+    func webLoadNSIage() {
+        let lastDateString = dateTimeUtils.getDateTimeString(addingDays: -60)
+        let currentTimeString = dateTimeUtils.getDateTimeString()
+
+        let parameters: [String: String] = [
+            "find[eventType]": NightscoutUtils.EventType.iage.rawValue,
+            "find[created_at][$gte]": lastDateString,
+            "find[created_at][$lte]": currentTimeString,
+            "count": "1"
+        ]
+
+        NightscoutUtils.executeRequest(eventType: .iage, parameters: parameters) { (result: Result<[iageData], Error>) in
+            switch result {
+            case .success(let data):
+                DispatchQueue.main.async {
+                    self.updateIage(data: data)
+                }
+            case .failure(let error):
+                print("Failed to fetch data: \(error.localizedDescription)")
+            }
+        }
+    }
+
+    // NS Sage Response Processor
+    func updateIage(data: [iageData]) {
+        infoManager.clearInfoData(type: .iage)
+
+        if data.count == 0 {
+            return
+        }
+        currentIage = data[0]
+        let lastIageString = data[0].created_at
+
+        let formatter = ISO8601DateFormatter()
+        formatter.formatOptions = [.withFullDate,
+                                   .withTime,
+                                   .withDashSeparatorInDate,
+                                   .withColonSeparatorInTime]
+
+        if let iageTime = formatter.date(from: (lastIageString as! String))?.timeIntervalSince1970 {
+            let now = dateTimeUtils.getNowTimeIntervalUTC()
+            let secondsAgo = now - iageTime
+
+            let formatter = DateComponentsFormatter()
+            formatter.unitsStyle = .positional
+            formatter.allowedUnits = [ .day, .hour]
+            formatter.zeroFormattingBehavior = [ .pad ]
+
+            if let formattedDuration = formatter.string(from: secondsAgo) {
+                infoManager.updateInfoData(type: .iage, value: formattedDuration)
+            }
+        }
+    }
+}

+ 10 - 1
LoopFollow/Controllers/Nightscout/Treatments.swift

@@ -51,7 +51,8 @@ extension MainViewController {
         var resumePump: [[String:AnyObject]] = []
         var pumpSiteChange: [cageData] = []
         var cgmSensorStart: [sageData] = []
-        
+        var insulinCartridge: [iageData] = []
+
         for entry in entries {
             guard let eventType = entry["eventType"] as? String else {
                 continue
@@ -96,6 +97,11 @@ extension MainViewController {
                     let newEntry = sageData(created_at: createdAt)
                     cgmSensorStart.append(newEntry)
                 }
+            case "Insulin Cartridge Change":
+                if let createdAt = entry["created_at"] as? String {
+                    let newEntry = iageData(created_at: createdAt)
+                    insulinCartridge.append(newEntry)
+                }
             default:
                 print("No Match: \(String(describing: entry))")
             }
@@ -168,6 +174,9 @@ extension MainViewController {
                 clearOldSensor()
             }
         }
+
+        processIage(entries: insulinCartridge)
+
         if note.count > 0 {
             processNotes(entries: note)
         } else {

+ 20 - 0
LoopFollow/Controllers/Nightscout/Treatments/InsulinCartridgeChange.swift

@@ -0,0 +1,20 @@
+//
+//  InsulinCartridgeChange.swift
+//  LoopFollow
+//
+//  Created by Jonas Björkert on 2024-08-05.
+//  Copyright © 2024 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+extension MainViewController {
+    func processIage(entries: [iageData]) {
+        if !entries.isEmpty {
+            updateIage(data: entries)
+        } else if let iage = currentIage {
+            updateIage(data: [iage])
+        } else {
+            webLoadNSIage()
+        }
+    }
+}

+ 2 - 1
LoopFollow/Helpers/NightscoutUtils.swift

@@ -46,10 +46,11 @@ class NightscoutUtils {
         case profile
         case treatments
         case deviceStatus
+        case iage = "Insulin Cartridge Change"
 
         var endpoint: String {
             switch self {
-            case .cage, .carbsToday, .sage, .treatments:
+            case .cage, .carbsToday, .sage, .treatments, .iage:
                 return "/api/v1/treatments.json"
             case .sgv:
                 return "/api/v1/entries.json"

+ 2 - 1
LoopFollow/InfoTable/InfoType.swift

@@ -9,7 +9,7 @@
 import Foundation
 
 enum InfoType: Int, CaseIterable {
-    case iob, cob, basal, override, battery, pump, sage, cage, recBolus, minMax, carbsToday, autosens, profile, target, isf, carbRatio, updated, tdd
+    case iob, cob, basal, override, battery, pump, sage, cage, recBolus, minMax, carbsToday, autosens, profile, target, isf, carbRatio, updated, tdd, iage
 
     var name: String {
         switch self {
@@ -31,6 +31,7 @@ enum InfoType: Int, CaseIterable {
         case .carbRatio: return "CR"
         case .updated: return "Updated"
         case .tdd: return "TDD"
+        case .iage: return "IAGE"
         }
     }
 

+ 39 - 11
LoopFollow/Storage/UserDefaults.swift

@@ -19,22 +19,50 @@ class UserDefaultsRepository {
     static let infoVisible = UserDefaultsValue<[Bool]>(key: "infoVisible", default: InfoType.allCases.map { $0.defaultVisible })
 
     static func synchronizeInfoTypes() {
-        // Ensure infoSort array is the correct size
+        // Print current state of arrays before synchronization
+        print("Before Synchronization:")
+        print("infoSort: \(infoSort.value)")
+        print("infoVisible: \(infoVisible.value)")
+
         var sortArray = infoSort.value
-        if sortArray.count != InfoType.allCases.count {
-            sortArray = InfoType.allCases.map { $0.sortOrder }
-            infoSort.value = sortArray
+        var visibleArray = infoVisible.value
+
+        // Current valid indices based on InfoType
+        let currentValidIndices = InfoType.allCases.map { $0.rawValue }
+
+        // Add missing indices to sortArray
+        for index in currentValidIndices {
+            if !sortArray.contains(index) {
+                sortArray.append(index) // Append missing types at the end
+                print("Added missing index \(index) to sortArray")
+            }
         }
 
-        // Ensure infoVisible array is the correct size
-        var visibleArray = infoVisible.value
-        if visibleArray.count < InfoType.allCases.count {
-            for infoType in InfoType.allCases[visibleArray.count..<InfoType.allCases.count] {
-                visibleArray.append(infoType.defaultVisible)
+        // Remove deprecated indices
+        sortArray = sortArray.filter { currentValidIndices.contains($0) }
+        print("Filtered sortArray to remove invalid indices: \(sortArray)")
+
+        // Ensure visibleArray is updated with new entries
+        if visibleArray.count < currentValidIndices.count {
+            for i in visibleArray.count..<currentValidIndices.count {
+                visibleArray.append(InfoType(rawValue: i)?.defaultVisible ?? false)
+                print("Added default visibility for new index \(i)")
             }
-        } else if visibleArray.count > InfoType.allCases.count {
-            visibleArray = Array(visibleArray.prefix(InfoType.allCases.count))
         }
+
+        // Trim excess elements if there are more than needed
+        if visibleArray.count > currentValidIndices.count {
+            visibleArray = Array(visibleArray.prefix(currentValidIndices.count))
+            print("Trimmed visibleArray to match current valid indices")
+        }
+
+        // Print updated state of arrays after synchronization
+        print("After Synchronization:")
+        print("infoSort: \(sortArray)")
+        print("infoVisible: \(visibleArray)")
+
+        // Save updated arrays
+        infoSort.value = sortArray
         infoVisible.value = visibleArray
     }
 

+ 32 - 22
LoopFollow/ViewControllers/InfoDisplaySettingsViewController.swift

@@ -42,30 +42,40 @@ class InfoDisplaySettingsViewController: FormViewController {
 
             for i in 0..<UserDefaultsRepository.infoSort.value.count {
                 let sortedIndex = UserDefaultsRepository.infoSort.value[i]
-                let infoType = InfoType(rawValue: sortedIndex)!
 
-                $0 <<< TextRow() { row in
-                    if(UserDefaultsRepository.infoVisible.value[sortedIndex]) {
-                        row.title = "\u{2713}\t\(infoType.name)"
-                    } else {
-                        row.title = "\u{2001}\t\(infoType.name)"
-                    }
-                }.onCellSelection { (cell, row) in
-                    let i = row.indexPath!.row
-                    let sortedIndex = UserDefaultsRepository.infoSort.value[i]
-                    UserDefaultsRepository.infoVisible.value[sortedIndex] = !UserDefaultsRepository.infoVisible.value[sortedIndex]
-
-                    self.tableView.reloadData()
-                }.cellSetup { (cell, row) in
-                    cell.textField.isUserInteractionEnabled = false
-                }.cellUpdate { (cell, row) in
-                    let sortedIndex = UserDefaultsRepository.infoSort.value[i]
-                    if(UserDefaultsRepository.infoVisible.value[sortedIndex]) {
-                        row.title = "\u{2713}\t\(infoType.name)"
-                    } else {
-                        row.title = "\u{2001}\t\(infoType.name)"
+                // Debug print to track the sortedIndex and corresponding InfoType
+                print("Index \(i): sortedIndex = \(sortedIndex)")
+
+                // Check if the sortedIndex maps to a valid InfoType
+                if let infoType = InfoType(rawValue: sortedIndex) {
+                    print("InfoType for sortedIndex \(sortedIndex): \(infoType.name)")
+
+                    $0 <<< TextRow() { row in
+                        if UserDefaultsRepository.infoVisible.value[sortedIndex] {
+                            row.title = "\u{2713}\t\(infoType.name)"
+                        } else {
+                            row.title = "\u{2001}\t\(infoType.name)"
+                        }
+                    }.onCellSelection { (cell, row) in
+                        let i = row.indexPath!.row
+                        let sortedIndex = UserDefaultsRepository.infoSort.value[i]
+                        UserDefaultsRepository.infoVisible.value[sortedIndex] = !UserDefaultsRepository.infoVisible.value[sortedIndex]
+
+                        self.tableView.reloadData()
+                    }.cellSetup { (cell, row) in
+                        cell.textField.isUserInteractionEnabled = false
+                    }.cellUpdate { (cell, row) in
+                        let sortedIndex = UserDefaultsRepository.infoSort.value[i]
+                        if UserDefaultsRepository.infoVisible.value[sortedIndex] {
+                            row.title = "\u{2713}\t\(infoType.name)"
+                        } else {
+                            row.title = "\u{2001}\t\(infoType.name)"
+                        }
+                        self.appStateController!.infoDataSettingsChanged = true
                     }
-                    self.appStateController!.infoDataSettingsChanged = true
+                } else {
+                    // Handle the case where sortedIndex doesn't map to a valid InfoType
+                    print("Warning: sortedIndex \(sortedIndex) does not map to a valid InfoType!")
                 }
             }
         }

+ 2 - 0
LoopFollow/ViewControllers/MainViewController.swift

@@ -64,6 +64,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
     var timeofLastBGUpdate = 0 as TimeInterval
     var currentSage : sageData?
     var currentCage : cageData?
+    var currentIage : iageData?
 
     var backgroundTask = BackgroundTask()
     
@@ -265,6 +266,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
         restartAllTimers()
         currentCage = nil
         currentSage = nil
+        currentIage = nil
         lastSpeechTime = nil
         refreshControl.endRefreshing()
     }