Explorar o código

Add: combined treatments downloader, bg check graphing

Jon Fawcett %!s(int64=5) %!d(string=hai) anos
pai
achega
0003b37df4

+ 33 - 0
LoopFollow/Controllers/Graphs.swift

@@ -168,6 +168,21 @@ extension MainViewController {
         lineOverride.highlightEnabled = true
         lineOverride.drawValuesEnabled = false
         
+        // BG Check
+        var chartEntryBGCheck = [ChartDataEntry]()
+        let lineBGCheck = LineChartDataSet(entries:chartEntryBGCheck, label: "")
+        lineBGCheck.circleRadius = 5
+        lineBGCheck.circleColors = [NSUIColor.systemRed.withAlphaComponent(0.75)]
+        lineBGCheck.drawCircleHoleEnabled = false
+        lineBGCheck.setDrawHighlightIndicators(false)
+        lineBGCheck.setColor(NSUIColor.systemRed, alpha: 1.0)
+        lineBGCheck.drawCirclesEnabled = true
+        lineBGCheck.lineWidth = 0
+        lineBGCheck.highlightEnabled = false
+        lineBGCheck.axisDependency = YAxis.AxisDependency.right
+        lineBGCheck.valueFormatter = ChartYDataValueFormatter()
+        lineBGCheck.drawValuesEnabled = false
+        
         // Setup the chart data of all lines
         let data = LineChartData()
         data.addDataSet(lineBG) // Dataset 0
@@ -177,6 +192,7 @@ extension MainViewController {
         data.addDataSet(lineCarbs) // Dataset 4
         data.addDataSet(lineBasalScheduled) // Dataset 5
         data.addDataSet(lineOverride) // Dataset 6
+        data.addDataSet(lineBGCheck) // Dataset 7
         
         data.setValueFont(UIFont.systemFont(ofSize: 12))
         
@@ -485,6 +501,23 @@ extension MainViewController {
         BGChart.notifyDataSetChanged()
     }
     
+    func updateBGCheckGraph() {
+        var dataIndex = 7
+        BGChart.lineData?.dataSets[dataIndex].clear()
+        for i in 0..<bgCheckData.count{
+            let formatter = NumberFormatter()
+            formatter.minimumFractionDigits = 0
+            formatter.maximumFractionDigits = 2
+            formatter.minimumIntegerDigits = 1
+            let value = ChartDataEntry(x: Double(bgCheckData[i].date), y: Double(bgCheckData[i].sgv), data: formatter.string(from: NSNumber(value: bgCheckData[i].sgv)))
+            BGChart.data?.dataSets[dataIndex].addEntry(value)
+
+        }
+        
+        BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
+        BGChart.data?.notifyDataChanged()
+        BGChart.notifyDataSetChanged()
+    }
  
     
     func createSmallBGGraph(){

+ 106 - 92
LoopFollow/Controllers/NightScout.swift

@@ -919,16 +919,17 @@ extension MainViewController {
         
     }
     
-    // NS Temp Basal Web Call
-    func WebLoadNSTempBasals() {
-        if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Download: Basal") }
-        if !UserDefaultsRepository.downloadBasal.value { return }
+    // NS Treatments Web Call
+    // Downloads Basal, Bolus, Carbs, BG Check, Notes, Overrides
+    func WebLoadNSTreatments() {
+        if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Download: Treatments") }
+        if !UserDefaultsRepository.downloadTreatments.value { return }
         
         let yesterdayString = dateTimeUtils.nowMinus24HoursTimeInterval()
         
-        var urlString = UserDefaultsRepository.url.value + "/api/v1/treatments.json?find[eventType][$eq]=Temp%20Basal&find[created_at][$gte]=" + yesterdayString
+        var urlString = UserDefaultsRepository.url.value + "/api/v1/treatments.json?find[created_at][$gte]=" + yesterdayString
         if token != "" {
-            urlString = UserDefaultsRepository.url.value + "/api/v1/treatments.json?token=" + token + "&find[eventType][$eq]=Temp%20Basal&find[created_at][$gte]=" + yesterdayString
+            urlString = UserDefaultsRepository.url.value + "/api/v1/treatments.json?token=" + token + "&find[created_at][$gte]=" + yesterdayString
         }
         
         guard let urlData = URL(string: urlString) else {
@@ -950,7 +951,7 @@ extension MainViewController {
             let json = try? (JSONSerialization.jsonObject(with: data) as? [[String:AnyObject]])
             if let json = json {
                 DispatchQueue.main.async {
-                    self.updateBasals(entries: json)
+                    self.updateTreatments(entries: json)
                 }
             } else {
                 return
@@ -959,8 +960,55 @@ extension MainViewController {
         task.resume()
     }
     
+    // Process and split out treatments to individual tasks
+    func updateTreatments(entries: [[String:AnyObject]]) {
+        
+        var tempBasal: [[String:AnyObject]] = []
+        var bolus: [[String:AnyObject]] = []
+        var carbs: [[String:AnyObject]] = []
+        var temporaryOverride: [[String:AnyObject]] = []
+        var note: [[String:AnyObject]] = []
+        var bgCheck: [[String:AnyObject]] = []
+        var suspendPump: [[String:AnyObject]] = []
+        var resumePump: [[String:AnyObject]] = []
+        var pumpSiteChange: [[String:AnyObject]] = []
+        
+        for i in 0..<entries.count {
+            let entry = entries[i] as [String : AnyObject]?
+            switch entry?["eventType"] as! String {
+                case "Temp Basal":
+                    tempBasal.append(entry!)
+                case "Correction Bolus":
+                    bolus.append(entry!)
+                case "Meal Bolus":
+                    carbs.append(entry!)
+                case "Temporary Override":
+                    temporaryOverride.append(entry!)
+                case "Note":
+                    note.append(entry!)
+                    print("Note: \(String(describing: entry))")
+                case "BG Check":
+                    bgCheck.append(entry!)
+                case "Suspend Pump":
+                    suspendPump.append(entry!)
+                case "Resume Pump":
+                    resumePump.append(entry!)
+                case "Pump Site Change":
+                    pumpSiteChange.append(entry!)
+                default:
+                    print("No Match: \(String(describing: entry))")
+            }
+        }
+        // end of for loop
+        
+        if tempBasal.count > 0 { processNSBasals(entries: tempBasal)}
+        if bolus.count > 0 { processNSBolus(entries: bolus)}
+        if carbs.count > 0 { processNSCarbs(entries: carbs)}
+        if bgCheck.count > 0 { processNSBGCheck(entries: bgCheck)}
+    }
+    
     // NS Temp Basal Response Processor
-    func updateBasals(entries: [[String:AnyObject]]) {
+    func processNSBasals(entries: [[String:AnyObject]]) {
         self.clearLastInfoData(index: 2)
         if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Process: Basal") }
         // due to temp basal durations, we're going to destroy the array and load everything each cycle for the time being.
@@ -1134,47 +1182,6 @@ extension MainViewController {
         infoTable.reloadData()
     }
     
-    // NS Bolus Web Call
-    func webLoadNSBoluses(){
-        if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Download: Bolus") }
-        if !UserDefaultsRepository.downloadBolus.value { return }
-        let yesterdayString = dateTimeUtils.nowMinus24HoursTimeInterval()
-        let urlUser = UserDefaultsRepository.url.value
-        var searchString = "find[eventType]=Correction%20Bolus&find[created_at][$gte]=" + yesterdayString
-        var urlDataPath: String = urlUser + "/api/v1/treatments.json?"
-        if token == "" {
-            urlDataPath = urlDataPath + searchString
-        }
-        else
-        {
-            urlDataPath = urlDataPath + "token=" + token + "&" + searchString
-        }
-        guard let urlData = URL(string: urlDataPath) else {
-            return
-        }
-        var request = URLRequest(url: urlData)
-        request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
-        let task = URLSession.shared.dataTask(with: request) { data, response, error in
-            
-            guard error == nil else {
-                return
-            }
-            guard let data = data else {
-                return
-            }
-            
-            let json = try? (JSONSerialization.jsonObject(with: data) as? [[String:AnyObject]])
-            if let json = json {
-                DispatchQueue.main.async {
-                    self.processNSBolus(entries: json)
-                }
-            } else {
-                return
-            }
-        }
-        task.resume()
-    }
-    
     // NS Meal Bolus Response Processor
     func processNSBolus(entries: [[String:AnyObject]]) {
         if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Process: Bolus") }
@@ -1224,49 +1231,7 @@ extension MainViewController {
         }
         
     }
-    
-    
-    // NS Carb Web Call
-    func webLoadNSCarbs(){
-        if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Download: Carbs") }
-        if !UserDefaultsRepository.downloadCarbs.value { return }
-        let yesterdayString = dateTimeUtils.nowMinus24HoursTimeInterval()
-        let urlUser = UserDefaultsRepository.url.value
-        var searchString = "find[eventType]=Meal%20Bolus&find[created_at][$gte]=" + yesterdayString
-        var urlDataPath: String = urlUser + "/api/v1/treatments.json?"
-        if token == "" {
-            urlDataPath = urlDataPath + searchString
-        }
-        else
-        {
-            urlDataPath = urlDataPath + "token=" + token + "&" + searchString
-        }
-        guard let urlData = URL(string: urlDataPath) else {
-            return
-        }
-        var request = URLRequest(url: urlData)
-        request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
-        let task = URLSession.shared.dataTask(with: request) { data, response, error in
-            
-            guard error == nil else {
-                return
-            }
-            guard let data = data else {
-                return
-            }
-            
-            let json = try? (JSONSerialization.jsonObject(with: data) as? [[String:AnyObject]])
-            if let json = json {
-                DispatchQueue.main.async {
-                    self.processNSCarbs(entries: json)
-                }
-            } else {
-                return
-            }
-        }
-        task.resume()
-    }
-    
+   
     // NS Carb Bolus Response Processor
     func processNSCarbs(entries: [[String:AnyObject]]) {
         if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Process: Carbs") }
@@ -1317,4 +1282,53 @@ extension MainViewController {
         
         
     }
+    
+    // NS BG Check Response Processor
+    func processNSBGCheck(entries: [[String:AnyObject]]) {
+        if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Process: BG Check") }
+        // because it's a small array, we're going to destroy and reload every time.
+        bgCheckData.removeAll()
+        for i in 0..<entries.count {
+            let currentEntry = entries[entries.count - 1 - i] as [String : AnyObject]?
+            var date: String
+            if currentEntry?["timestamp"] != nil {
+                date = currentEntry?["timestamp"] as! String
+            } else if currentEntry?["created_at"] != nil {
+                date = currentEntry?["created_at"] as! String
+            } else {
+                return
+            }
+            // Fix for FreeAPS milliseconds in timestamp
+            var strippedZone = String(date.dropLast())
+            strippedZone = strippedZone.components(separatedBy: ".")[0]
+            
+            let dateFormatter = DateFormatter()
+            dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
+            dateFormatter.locale = Locale(identifier: "en_US")
+            dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
+            let dateString = dateFormatter.date(from: strippedZone)
+            let dateTimeStamp = dateString!.timeIntervalSince1970
+            
+            guard let sgv = currentEntry?["glucose"] as? Int else {
+                if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "ERROR: Non-Int Glucose entry")}
+                continue
+            }
+            
+            if dateTimeStamp < (dateTimeUtils.getNowTimeIntervalUTC() + (60 * 60)) {
+                // Make the dot
+                //let dot = ShareGlucoseData(value: Double(carbs), date: Double(dateTimeStamp), sgv: Int(sgv.sgv))
+                let dot = ShareGlucoseData(sgv: sgv, date: Double(dateTimeStamp), direction: "")
+                bgCheckData.append(dot)
+            }
+            
+            
+            
+        }
+        
+        if UserDefaultsRepository.graphCarbs.value {
+            updateBGCheckGraph()
+        }
+        
+        
+    }
 }

+ 2 - 8
LoopFollow/Controllers/Timers.swift

@@ -195,14 +195,8 @@ extension MainViewController {
         }
         
         if !isStaleData() && UserDefaultsRepository.url.value != "" {
-            if UserDefaultsRepository.downloadBasal.value {
-                WebLoadNSTempBasals()
-            }
-            if UserDefaultsRepository.downloadBolus.value {
-                webLoadNSBoluses()
-            }
-            if UserDefaultsRepository.downloadCarbs.value {
-                webLoadNSCarbs()
+            if UserDefaultsRepository.downloadTreatments.value {
+                WebLoadNSTreatments()
             }
             startTreatmentsTimer()
         }

+ 0 - 12
LoopFollow/ViewControllers/GeneralSettingsViewController.swift

@@ -53,18 +53,6 @@ class GeneralSettingsViewController: FormViewController {
                     guard let value = row.value else { return }
                     UserDefaultsRepository.backgroundRefresh.value = value
             }
-        <<< StepperRow("backgroundRefreshFrequency") { row in
-            row.title = "Refresh Minutes"
-            row.tag = "backgroundRefreshFrequency"
-            row.cell.stepper.stepValue = 0.25
-            row.cell.stepper.minimumValue = 0.25
-            row.cell.stepper.maximumValue = 10
-            row.value = Double(UserDefaultsRepository.backgroundRefreshFrequency.value)
-            row.hidden = "$backgroundRefresh == false"
-        }.onChange { [weak self] row in
-                guard let value = row.value else { return }
-                UserDefaultsRepository.backgroundRefreshFrequency.value = value
-        }
         <<< SwitchRow("persistentNotification") { row in
         row.title = "Persistent Notification"
         row.value = UserDefaultsRepository.persistentNotification.value

+ 1 - 0
LoopFollow/ViewControllers/MainViewController.swift

@@ -107,6 +107,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
     var carbData: [bolusCarbGraphStruct] = []
     var overrideData: [DataStructs.overrideGraphStruct] = []
     var predictionData: [ShareGlucoseData] = []
+    var bgCheckData: [ShareGlucoseData] = []
     var chartData = LineChartData()
     var newBGPulled = false
     var lastCalDate: Double = 0

+ 1 - 0
LoopFollow/repository/UserDefaults.swift

@@ -71,6 +71,7 @@ class UserDefaultsRepository {
     })
     
     // Debug Settings
+        static let downloadTreatments = UserDefaultsValue<Bool>(key: "downloadTreatments", default: true)
         static let downloadBasal = UserDefaultsValue<Bool>(key: "downloadBasal", default: true)
         static let downloadBolus = UserDefaultsValue<Bool>(key: "downloadBolus", default: true)
         static let downloadCarbs = UserDefaultsValue<Bool>(key: "downloadCarbs", default: true)