Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate the display of Automated and Manual boluses #305

Merged
merged 5 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions LoopFollow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
DD493AE92ACF2445009A6922 /* BGData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD493AE82ACF2445009A6922 /* BGData.swift */; };
DD608A082C1F584900F91132 /* DeviceStatusLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A072C1F584900F91132 /* DeviceStatusLoop.swift */; };
DD608A0C2C27415C00F91132 /* BackgroundAlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD608A0B2C27415C00F91132 /* BackgroundAlertManager.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 */; };
Expand Down Expand Up @@ -216,6 +217,7 @@
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>"; };
DD608A0B2C27415C00F91132 /* BackgroundAlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundAlertManager.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>"; };
Expand Down Expand Up @@ -442,6 +444,7 @@
DD493ADA2ACF21A3009A6922 /* Bolus.swift */,
DD493AD42ACF2109009A6922 /* ResumePump.swift */,
DDF9676D2AD08C6E00C5EB95 /* SiteChange.swift */,
DD608A092C23593900F91132 /* SMB.swift */,
);
path = Treatments;
sourceTree = "<group>";
Expand Down Expand Up @@ -992,6 +995,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 */,
Expand Down
168 changes: 145 additions & 23 deletions LoopFollow/Controllers/Graphs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,46 @@ import Foundation
import Charts
import UIKit

import Charts

class TriangleRenderer: LineChartRenderer {
let smbDataSetIndex: Int

init(dataProvider: LineChartDataProvider?, animator: Animator?, viewPortHandler: ViewPortHandler?, smbDataSetIndex: Int) {
self.smbDataSetIndex = smbDataSetIndex
super.init(dataProvider: dataProvider!, animator: animator!, viewPortHandler: viewPortHandler!)
}

override func drawExtras(context: CGContext) {
super.drawExtras(context: context)

guard let dataProvider = dataProvider else { return }

if dataProvider.lineData?.dataSets.count ?? 0 > smbDataSetIndex, let lineDataSet = dataProvider.lineData?.dataSets[smbDataSetIndex] as? LineChartDataSet {
let trans = dataProvider.getTransformer(forAxis: lineDataSet.axisDependency)
let phaseY = animator.phaseY

for j in 0 ..< lineDataSet.entryCount {
guard let e = lineDataSet.entryForIndex(j) else { continue }

let pt = trans.pixelForValues(x: e.x, y: e.y * phaseY)

context.saveGState()
context.beginPath()
context.move(to: CGPoint(x: pt.x, y: pt.y + 9))
context.addLine(to: CGPoint(x: pt.x - 5, y: pt.y - 1))
context.addLine(to: CGPoint(x: pt.x + 5, y: pt.y - 1))
context.closePath()

context.setFillColor(lineDataSet.circleColors.first!.cgColor)
context.fillPath()

context.restoreGState()
}
}
}
}

let ScaleXMax:Float = 150.0
extension MainViewController {

Expand Down Expand Up @@ -350,6 +390,30 @@ 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.systemBlue.withAlphaComponent(1.0)]
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.drawCirclesEnabled = false
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()
Expand All @@ -370,6 +434,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))

Expand Down Expand Up @@ -764,17 +829,7 @@ extension MainViewController {
let bolusShift = findNextBolusTime(timeWithin: 240, needle: bolusData[i].date, haystack: bolusData, startingIndex: i)
var dateTimeStamp = bolusData[i].date

// Alpha colors for DIA
let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
if diffTimeHours <= 1 {
colors.append(NSUIColor.systemBlue.withAlphaComponent(1.0))
} else if diffTimeHours > 6 {
colors.append(NSUIColor.systemBlue.withAlphaComponent(0.25))
} else {
let thisAlpha = 1.0 - (0.15 * diffTimeHours)
colors.append(NSUIColor.systemBlue.withAlphaComponent(CGFloat(thisAlpha)))
}
colors.append(NSUIColor.systemBlue.withAlphaComponent(1.0))

if bolusShift {
// Move it half the distance between BG readings
Expand Down Expand Up @@ -819,6 +874,64 @@ 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

let bolusShift = findNextBolusTime(timeWithin: 240, needle: smbData[i].date, haystack: smbData, startingIndex: i)
var dateTimeStamp = smbData[i].date

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 {
dateTimeStamp = dateTimeStamp - 150
}

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)
}
}

let smbRenderer = TriangleRenderer(dataProvider: BGChart, animator: Animator(), viewPortHandler: BGChart.viewPortHandler, smbDataSetIndex: dataIndex)
BGChart.renderer = smbRenderer

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
Expand Down Expand Up @@ -846,17 +959,7 @@ extension MainViewController {
let carbShift = findNextCarbTime(timeWithin: 250, needle: carbData[i].date, haystack: carbData, startingIndex: i)
var dateTimeStamp = carbData[i].date

// Alpha colors for DIA
let nowTime = dateTimeUtils.getNowTimeIntervalUTC()
let diffTimeHours = (nowTime - dateTimeStamp) / 60 / 60
if diffTimeHours <= 0.5 {
colors.append(NSUIColor.systemOrange.withAlphaComponent(1.0))
} else if diffTimeHours > Double(hours) {
colors.append(NSUIColor.systemOrange.withAlphaComponent(0.25))
} else {
let thisAlpha = 1.0 - ((0.75 / Double(hours)) * diffTimeHours)
colors.append(NSUIColor.systemOrange.withAlphaComponent(CGFloat(thisAlpha)))
}
colors.append(NSUIColor.systemOrange.withAlphaComponent(1.0))

// skip if outside of visible area
let graphHours = 24 * UserDefaultsRepository.downloadDays.value
Expand All @@ -866,7 +969,6 @@ extension MainViewController {
dateTimeStamp = dateTimeStamp - 250
}


let dot = ChartDataEntry(x: Double(dateTimeStamp), y: Double(carbData[i].sgv), data: valueString)
BGChart.data?.dataSets[dataIndex].addEntry(dot)
if UserDefaultsRepository.smallGraphTreatments.value {
Expand Down Expand Up @@ -1290,6 +1392,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
Expand All @@ -1308,6 +1429,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
Expand Down
6 changes: 6 additions & 0 deletions LoopFollow/Controllers/NightScout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ extension MainViewController {
updateBolusGraph()
}

func clearOldSmb()
{
smbData.removeAll()
updateSmbGraph()
}

func clearOldCarb()
{
carbData.removeAll()
Expand Down
18 changes: 16 additions & 2 deletions LoopFollow/Controllers/Nightscout/Treatments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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]] = []
Expand All @@ -58,8 +59,14 @@ extension MainViewController {
switch eventType {
case "Temp Basal":
tempBasal.append(entry)
case "Correction Bolus", "Bolus", "SMB":
bolus.append(entry)
case "Correction Bolus", "Bolus":
if let automatic = entry["automatic"] as? Bool, automatic {
smb.append(entry)
} else {
bolus.append(entry)
}
case "SMB":
smb.append(entry)
case "Meal Bolus":
carbs.append(entry)
bolus.append(entry)
Expand Down Expand Up @@ -105,6 +112,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)
Expand Down
44 changes: 44 additions & 0 deletions LoopFollow/Controllers/Nightscout/Treatments/SMB.swift
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions LoopFollow/ViewControllers/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []
Expand Down