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

Differentiating the display of SMBs from boluses.

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

+ 4 - 0
LoopFollow.xcodeproj/project.pbxproj

@@ -22,6 +22,7 @@
 		DD493AE72ACF23CF009A6922 /* DeviceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE62ACF23CF009A6922 /* DeviceStatus.swift */; };
 		DD493AE92ACF2445009A6922 /* BGData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE82ACF2445009A6922 /* BGData.swift */; };
 		DD608A082C1F584900F91132 /* DeviceStatusLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A072C1F584900F91132 /* DeviceStatusLoop.swift */; };
+		DD608A0A2C23593900F91132 /* SMB.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A092C23593900F91132 /* SMB.swift */; };
 		DD6A935E2BFA6FA2003FFB8E /* DeviceStatusOpenAPS.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6A935D2BFA6FA2003FFB8E /* DeviceStatusOpenAPS.swift */; };
 		DD7E19842ACDA50C00DBD158 /* Overrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E19832ACDA50C00DBD158 /* Overrides.swift */; };
 		DD7E19862ACDA59700DBD158 /* BGCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E19852ACDA59700DBD158 /* BGCheck.swift */; };
@@ -214,6 +215,7 @@
 		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>"; };
 		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>"; };
 		DD6A935D2BFA6FA2003FFB8E /* DeviceStatusOpenAPS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceStatusOpenAPS.swift; sourceTree = "<group>"; };
 		DD7E19832ACDA50C00DBD158 /* Overrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Overrides.swift; sourceTree = "<group>"; };
 		DD7E19852ACDA59700DBD158 /* BGCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGCheck.swift; sourceTree = "<group>"; };
@@ -440,6 +442,7 @@
 				DD493ADA2ACF21A3009A6922 /* Bolus.swift */,
 				DD493AD42ACF2109009A6922 /* ResumePump.swift */,
 				DDF9676D2AD08C6E00C5EB95 /* SiteChange.swift */,
+				DD608A092C23593900F91132 /* SMB.swift */,
 			);
 			path = Treatments;
 			sourceTree = "<group>";
@@ -989,6 +992,7 @@
 				FCC6886724898F8000A0279D /* UserDefaultsValue.swift in Sources */,
 				DDCF979E24C2382A002C9752 /* AppStateController.swift in Sources */,
 				FC97881E2485969B00A7906C /* NightScoutViewController.swift in Sources */,
+				DD608A0A2C23593900F91132 /* SMB.swift in Sources */,
 				DDCF979824C1489C002C9752 /* GraphSettingsViewController.swift in Sources */,
 				FC3AE7B5249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld in Sources */,
 				FCC6886F2489A53800A0279D /* AppConstants.swift in Sources */,

+ 123 - 0
LoopFollow/Controllers/Graphs.swift

@@ -350,6 +350,32 @@ extension MainViewController {
         }
         ZTlinePrediction.setDrawHighlightIndicators(false)
         ZTlinePrediction.valueFont.withSize(50)
+
+        // SMB
+        let chartEntrySmb = [ChartDataEntry]()
+        let lineSmb = LineChartDataSet(entries:chartEntrySmb, label: "")
+        lineSmb.circleRadius = CGFloat(globalVariables.dotBolus)
+        lineSmb.circleColors = [NSUIColor.red.withAlphaComponent(0.75)]
+        lineSmb.drawCircleHoleEnabled = false
+        lineSmb.setDrawHighlightIndicators(false)
+        lineSmb.setColor(NSUIColor.red, alpha: 1.0)
+        lineSmb.lineWidth = 0
+        lineSmb.axisDependency = YAxis.AxisDependency.right
+        lineSmb.valueFormatter = ChartYDataValueFormatter()
+        lineSmb.valueTextColor = NSUIColor.label
+        lineSmb.fillColor = NSUIColor.red
+        lineSmb.fillAlpha = 0.6
+        
+        lineSmb.drawCirclesEnabled = true
+        lineSmb.drawFilledEnabled = false
+        
+        if UserDefaultsRepository.showValues.value  {
+            lineSmb.drawValuesEnabled = true
+            lineSmb.highlightEnabled = false
+        } else {
+            lineSmb.drawValuesEnabled = false
+            lineSmb.highlightEnabled = true
+        }
         
         // Setup the chart data of all lines
         let data = LineChartData()
@@ -370,6 +396,7 @@ extension MainViewController {
         data.append(IOBlinePrediction) // Dataset 13
         data.append(COBlinePrediction) // Dataset 14
         data.append(UAMlinePrediction) // Dataset 15
+        data.append(lineSmb) // Dataset 16
 
         data.setValueFont(UIFont.systemFont(ofSize: 12))
         
@@ -819,6 +846,82 @@ extension MainViewController {
         }
     }
     
+    func updateSmbGraph() {
+        var dataIndex = 16
+        var yTop: Double = 370
+        var yBottom: Double = 345
+        var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
+        var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
+        mainChart.clear()
+        smallChart.clear()
+        let lightBlue = NSUIColor(red: 135/255, green: 206/255, blue: 235/255, alpha: 1.0) // Light Sky Blue
+
+        var colors = [NSUIColor]()
+        for i in 0..<smbData.count{
+            let formatter = NumberFormatter()
+            formatter.minimumFractionDigits = 0
+            formatter.maximumFractionDigits = 2
+            formatter.minimumIntegerDigits = 0
+            
+            // Check overlapping carbs to shift left if needed
+            let bolusShift = findNextBolusTime(timeWithin: 240, needle: smbData[i].date, haystack: smbData, startingIndex: i)
+            var dateTimeStamp = smbData[i].date
+            
+            // Alpha colors for DIA
+            let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
+            let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
+            if diffTimeHours <= 1 {
+                colors.append(lightBlue.withAlphaComponent(1.0))
+            } else if diffTimeHours > 6 {
+                colors.append(lightBlue.withAlphaComponent(0.25))
+            } else {
+                let thisAlpha = 1.0 - (0.15 * diffTimeHours)
+                colors.append(lightBlue.withAlphaComponent(CGFloat(thisAlpha)))
+            }
+            
+            if bolusShift {
+                // Move it half the distance between BG readings
+                dateTimeStamp = dateTimeStamp - 150
+            }
+            
+            // skip if outside of visible area
+            let graphHours = 24 * UserDefaultsRepository.downloadDays.value
+            if dateTimeStamp < dateTimeUtils.getTimeIntervalNHoursAgo(N: graphHours) { continue }
+            
+            let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(smbData[i].sgv), data: formatter.string(from: NSNumber(value: smbData[i].value)))
+            mainChart.addEntry(dot)
+            if UserDefaultsRepository.smallGraphTreatments.value {
+                smallChart.addEntry(dot)
+            }
+        }
+        
+        // Set Colors
+        let lineBolus = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
+        let lineBolusSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
+        lineBolus.colors.removeAll()
+        lineBolus.circleColors.removeAll()
+        lineBolusSmall.colors.removeAll()
+        lineBolusSmall.circleColors.removeAll()
+        
+        if colors.count > 0 {
+            for i in 0..<colors.count{
+                mainChart.addColor(colors[i])
+                mainChart.circleColors.append(colors[i])
+                smallChart.addColor(colors[i])
+                smallChart.circleColors.append(colors[i])
+            }
+        }
+        
+        BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
+        BGChart.data?.notifyDataChanged()
+        BGChart.notifyDataSetChanged()
+        if UserDefaultsRepository.smallGraphTreatments.value {
+            BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
+            BGChartFull.data?.notifyDataChanged()
+            BGChartFull.notifyDataSetChanged()
+        }
+    }
+    
     func updateCarbGraph() {
         var dataIndex = 4
         var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
@@ -1290,6 +1393,25 @@ extension MainViewController {
         ZTlinePrediction.lineWidth = 1.5
         ZTlinePrediction.axisDependency = YAxis.AxisDependency.right
         
+        // SMB
+        var chartEntrySmb = [ChartDataEntry]()
+        let lineSmb = LineChartDataSet(entries:chartEntrySmb, label: "")
+        lineSmb.circleRadius = 2
+        lineSmb.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
+        lineSmb.drawCircleHoleEnabled = false
+        lineSmb.setDrawHighlightIndicators(false)
+        lineSmb.setColor(NSUIColor.systemBlue, alpha: 1.0)
+        lineSmb.lineWidth = 0
+        lineSmb.axisDependency = YAxis.AxisDependency.right
+        lineSmb.valueFormatter = ChartYDataValueFormatter()
+        lineSmb.valueTextColor = NSUIColor.label
+        lineSmb.fillColor = NSUIColor.systemBlue
+        lineSmb.fillAlpha = 0.6
+        lineSmb.drawCirclesEnabled = true
+        lineSmb.drawFilledEnabled = false
+        lineSmb.drawValuesEnabled = false
+        lineSmb.highlightEnabled = false
+        
         // Setup the chart data of all lines
         let data = LineChartData()
         data.append(lineBG) // Dataset 0
@@ -1308,6 +1430,7 @@ extension MainViewController {
         data.append(IOBlinePrediction) // Dataset 13
         data.append(COBlinePrediction) // Dataset 14
         data.append(UAMlinePrediction) // Dataset 15
+        data.append(lineSmb) // Dataset 16
 
         BGChartFull.highlightPerDragEnabled = true
         BGChartFull.leftAxis.enabled = false

+ 6 - 0
LoopFollow/Controllers/NightScout.swift

@@ -90,6 +90,12 @@ extension MainViewController {
         updateBolusGraph()
     }
     
+    func clearOldSmb()
+    {
+        smbData.removeAll()
+        updateSmbGraph()
+    }
+
     func clearOldCarb()
     {
         carbData.removeAll()

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

@@ -41,6 +41,7 @@ extension MainViewController {
         
         var tempBasal: [[String:AnyObject]] = []
         var bolus: [[String:AnyObject]] = []
+        var smb: [[String:AnyObject]] = []
         var carbs: [[String:AnyObject]] = []
         var temporaryOverride: [[String:AnyObject]] = []
         var note: [[String:AnyObject]] = []
@@ -58,8 +59,10 @@ extension MainViewController {
             switch eventType {
             case "Temp Basal":
                 tempBasal.append(entry)
-            case "Correction Bolus", "Bolus", "SMB":
+            case "Correction Bolus", "Bolus":
                 bolus.append(entry)
+            case "SMB":
+                smb.append(entry)
             case "Meal Bolus":
                 carbs.append(entry)
                 bolus.append(entry)
@@ -105,6 +108,13 @@ extension MainViewController {
                 clearOldBolus()
             }
         }
+        if smb.count > 0 {
+            processNSSmb(entries: smb)
+        } else {
+            if smbData.count > 0 {
+                clearOldSmb()
+            }
+        }
         updateTodaysCarbsFromEntries(entries: carbs)
         if carbs.count > 0 {
             processNSCarbs(entries: carbs)

+ 44 - 0
LoopFollow/Controllers/Nightscout/Treatments/SMB.swift

@@ -0,0 +1,44 @@
+//
+//  SMB.swift
+//  LoopFollow
+//
+//  Created by Jonas Björkert on 2024-06-19.
+//  Copyright © 2024 Jon Fawcett. All rights reserved.
+//
+
+import Foundation
+extension MainViewController {
+    // NS SMB Processor
+    func processNSSmb(entries: [[String:AnyObject]]) {
+        smbData.removeAll()
+        var lastFoundIndex = 0
+        
+        entries.reversed().forEach { currentEntry in
+            var bolusDate: String
+            if currentEntry["timestamp"] != nil {
+                bolusDate = currentEntry["timestamp"] as! String
+            } else if currentEntry["created_at"] != nil {
+                bolusDate = currentEntry["created_at"] as! String
+            } else {
+                return
+            }
+            
+            guard let parsedDate = NightscoutUtils.parseDate(bolusDate),
+                  let bolus = currentEntry["insulin"] as? Double else { return }
+            
+            let dateTimeStamp = parsedDate.timeIntervalSince1970
+            let sgv = findNearestBGbyTime(needle: dateTimeStamp, haystack: bgData, startingIndex: lastFoundIndex)
+            lastFoundIndex = sgv.foundIndex
+            
+            if dateTimeStamp < (dateTimeUtils.getNowTimeIntervalUTC() + (60 * 60)) {
+                // Make the dot
+                let dot = bolusGraphStruct(value: bolus, date: Double(dateTimeStamp), sgv: Int(sgv.sgv + 20))
+                smbData.append(dot)
+            }
+        }
+        
+        if UserDefaultsRepository.graphBolus.value {
+            updateSmbGraph()
+        }
+    }
+}

+ 1 - 0
LoopFollow/ViewControllers/MainViewController.swift

@@ -109,6 +109,7 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
     var basalData: [basalGraphStruct] = []
     var basalScheduleData: [basalGraphStruct] = []
     var bolusData: [bolusGraphStruct] = []
+    var smbData: [bolusGraphStruct] = []
     var carbData: [carbGraphStruct] = []
     var overrideGraphData: [DataStructs.overrideStruct] = []
     var predictionData: [ShareGlucoseData] = []