|
|
@@ -8,259 +8,225 @@ import UIKit
|
|
|
import HealthKit
|
|
|
|
|
|
extension MainViewController {
|
|
|
- func DeviceStatusOpenAPS(formatter: ISO8601DateFormatter, lastDeviceStatus: [String: AnyObject]?, lastLoopRecord: [String: AnyObject], jsonDeviceStatus: [[String:AnyObject]]) {
|
|
|
- if let createdAtString = lastDeviceStatus?["created_at"] as? String,
|
|
|
- let lastLoopTime = formatter.date(from: createdAtString)?.timeIntervalSince1970 {
|
|
|
- ObservableUserDefaults.shared.device.value = lastDeviceStatus?["device"] as? String ?? ""
|
|
|
- if lastLoopRecord["failureReason"] != nil {
|
|
|
- LoopStatusLabel.text = "X"
|
|
|
- latestLoopStatusString = "X"
|
|
|
- evaluateNotLooping(lastLoopTime: UserDefaultsRepository.alertLastLoopTime.value)
|
|
|
- } else {
|
|
|
- guard let enactedOrSuggested = lastLoopRecord["enacted"] as? [String: AnyObject] ?? lastLoopRecord["suggested"] as? [String: AnyObject] else {
|
|
|
- LoopStatusLabel.text = "↻"
|
|
|
- latestLoopStatusString = "↻"
|
|
|
- evaluateNotLooping(lastLoopTime: UserDefaultsRepository.alertLastLoopTime.value)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- var wasEnacted : Bool
|
|
|
- if let enacted = lastLoopRecord["enacted"] as? [String: AnyObject] {
|
|
|
- wasEnacted = NSDictionary(dictionary: enacted).isEqual(to: enactedOrSuggested)
|
|
|
- } else {
|
|
|
- wasEnacted = false
|
|
|
- }
|
|
|
-
|
|
|
- Observable.shared.isLastDeviceStatusSuggested.value = !wasEnacted
|
|
|
+ func DeviceStatusOpenAPS(formatter: ISO8601DateFormatter, lastDeviceStatus: [String: AnyObject]?, lastLoopRecord: [String: AnyObject]) {
|
|
|
+ ObservableUserDefaults.shared.device.value = lastDeviceStatus?["device"] as? String ?? ""
|
|
|
+ if lastLoopRecord["failureReason"] != nil {
|
|
|
+ LoopStatusLabel.text = "X"
|
|
|
+ latestLoopStatusString = "X"
|
|
|
+ } else {
|
|
|
+ guard let enactedOrSuggested = lastLoopRecord["suggested"] as? [String: AnyObject] ?? lastLoopRecord["enacted"] as? [String: AnyObject] else {
|
|
|
+ LoopStatusLabel.text = "↻"
|
|
|
+ latestLoopStatusString = "↻"
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- if wasEnacted {
|
|
|
+ var wasEnacted : Bool
|
|
|
+ if let enacted = lastLoopRecord["enacted"] as? [String: AnyObject] {
|
|
|
+ wasEnacted = true
|
|
|
+ if let timestampString = enacted["timestamp"] as? String,
|
|
|
+ let lastLoopTime = formatter.date(from: timestampString)?.timeIntervalSince1970 {
|
|
|
UserDefaultsRepository.alertLastLoopTime.value = lastLoopTime
|
|
|
LogManager.shared.log(category: .deviceStatus, message: "New LastLoopTime: \(lastLoopTime)", isDebug: true)
|
|
|
-
|
|
|
- evaluateNotLooping(lastLoopTime: UserDefaultsRepository.alertLastLoopTime.value)
|
|
|
- } else {
|
|
|
- LogManager.shared.log(category: .deviceStatus, message: "Last devicestatus was not enacted")
|
|
|
- findFallbackEnactedAndSetLoopTime(in: jsonDeviceStatus, formatter: formatter)
|
|
|
}
|
|
|
+ } else {
|
|
|
+ wasEnacted = false
|
|
|
+ LogManager.shared.log(category: .deviceStatus, message: "Last devicestatus is missing enacted")
|
|
|
+ }
|
|
|
|
|
|
- if let timestamp = enactedOrSuggested["timestamp"] as? String,
|
|
|
- let enactedTime = formatter.date(from: timestamp)?.timeIntervalSince1970 {
|
|
|
- let formattedTime = Localizer.formatTimestampToLocalString(enactedTime)
|
|
|
- infoManager.updateInfoData(type: .updated, value: formattedTime)
|
|
|
- }
|
|
|
+ var updatedTime: TimeInterval?
|
|
|
|
|
|
- // ISF
|
|
|
- let profileISF = profileManager.currentISF()
|
|
|
- var enactedISF: HKQuantity?
|
|
|
- if let enactedISFValue = enactedOrSuggested["ISF"] as? Double {
|
|
|
- var determinedISFUnit: HKUnit = .milligramsPerDeciliter
|
|
|
- if enactedISFValue < 15 {
|
|
|
- determinedISFUnit = .millimolesPerLiter
|
|
|
- }
|
|
|
- enactedISF = HKQuantity(unit: determinedISFUnit, doubleValue: enactedISFValue)
|
|
|
- }
|
|
|
- if let profileISF = profileISF, let enactedISF = enactedISF, profileISF != enactedISF {
|
|
|
- infoManager.updateInfoData(type: .isf, firstValue: profileISF, secondValue: enactedISF, separator: .arrow)
|
|
|
- } else if let profileISF = profileISF {
|
|
|
- infoManager.updateInfoData(type: .isf, value: profileISF)
|
|
|
+ if let timestamp = enactedOrSuggested["timestamp"] as? String,
|
|
|
+ let parsedTime = formatter.date(from: timestamp)?.timeIntervalSince1970 {
|
|
|
+ updatedTime = parsedTime
|
|
|
+ let formattedTime = Localizer.formatTimestampToLocalString(parsedTime)
|
|
|
+ infoManager.updateInfoData(type: .updated, value: formattedTime)
|
|
|
+ }
|
|
|
+
|
|
|
+ // ISF
|
|
|
+ let profileISF = profileManager.currentISF()
|
|
|
+ var enactedISF: HKQuantity?
|
|
|
+ if let enactedISFValue = enactedOrSuggested["ISF"] as? Double {
|
|
|
+ var determinedISFUnit: HKUnit = .milligramsPerDeciliter
|
|
|
+ if enactedISFValue < 15 {
|
|
|
+ determinedISFUnit = .millimolesPerLiter
|
|
|
}
|
|
|
+ enactedISF = HKQuantity(unit: determinedISFUnit, doubleValue: enactedISFValue)
|
|
|
+ }
|
|
|
+ if let profileISF = profileISF, let enactedISF = enactedISF, profileISF != enactedISF {
|
|
|
+ infoManager.updateInfoData(type: .isf, firstValue: profileISF, secondValue: enactedISF, separator: .arrow)
|
|
|
+ } else if let profileISF = profileISF {
|
|
|
+ infoManager.updateInfoData(type: .isf, value: profileISF)
|
|
|
+ }
|
|
|
|
|
|
- // Carb Ratio (CR)
|
|
|
- let profileCR = profileManager.currentCarbRatio()
|
|
|
- var enactedCR: Double?
|
|
|
- if let reasonString = enactedOrSuggested["reason"] as? String {
|
|
|
- let pattern = "CR: (\\d+(?:\\.\\d+)?)"
|
|
|
- if let regex = try? NSRegularExpression(pattern: pattern) {
|
|
|
- let nsString = reasonString as NSString
|
|
|
- if let match = regex.firstMatch(in: reasonString, range: NSRange(location: 0, length: nsString.length)) {
|
|
|
- let crString = nsString.substring(with: match.range(at: 1))
|
|
|
- enactedCR = Double(crString)
|
|
|
- }
|
|
|
+ // Carb Ratio (CR)
|
|
|
+ let profileCR = profileManager.currentCarbRatio()
|
|
|
+ var enactedCR: Double?
|
|
|
+ if let reasonString = enactedOrSuggested["reason"] as? String {
|
|
|
+ let pattern = "CR: (\\d+(?:\\.\\d+)?)"
|
|
|
+ if let regex = try? NSRegularExpression(pattern: pattern) {
|
|
|
+ let nsString = reasonString as NSString
|
|
|
+ if let match = regex.firstMatch(in: reasonString, range: NSRange(location: 0, length: nsString.length)) {
|
|
|
+ let crString = nsString.substring(with: match.range(at: 1))
|
|
|
+ enactedCR = Double(crString)
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if let profileCR = profileCR, let enactedCR = enactedCR, profileCR != enactedCR {
|
|
|
- infoManager.updateInfoData(type: .carbRatio, value: profileCR, enactedValue: enactedCR, separator: .arrow)
|
|
|
- } else if let profileCR = profileCR {
|
|
|
- infoManager.updateInfoData(type: .carbRatio, value: profileCR)
|
|
|
- }
|
|
|
+ if let profileCR = profileCR, let enactedCR = enactedCR, profileCR != enactedCR {
|
|
|
+ infoManager.updateInfoData(type: .carbRatio, value: profileCR, enactedValue: enactedCR, separator: .arrow)
|
|
|
+ } else if let profileCR = profileCR {
|
|
|
+ infoManager.updateInfoData(type: .carbRatio, value: profileCR)
|
|
|
+ }
|
|
|
|
|
|
- // IOB
|
|
|
- if let iobMetric = InsulinMetric(from: lastLoopRecord["iob"], key: "iob") {
|
|
|
- infoManager.updateInfoData(type: .iob, value: iobMetric)
|
|
|
- latestIOB = iobMetric
|
|
|
- }
|
|
|
+ // IOB
|
|
|
+ if let iobMetric = InsulinMetric(from: lastLoopRecord["iob"], key: "iob") {
|
|
|
+ infoManager.updateInfoData(type: .iob, value: iobMetric)
|
|
|
+ latestIOB = iobMetric
|
|
|
+ }
|
|
|
|
|
|
- // COB
|
|
|
- if let cobMetric = CarbMetric(from: enactedOrSuggested, key: "COB") {
|
|
|
- infoManager.updateInfoData(type: .cob, value: cobMetric)
|
|
|
- latestCOB = cobMetric
|
|
|
- } else if let reasonString = enactedOrSuggested["reason"] as? String {
|
|
|
- // Fallback: Extract COB from reason string
|
|
|
- let cobPattern = "COB: (\\d+(?:\\.\\d+)?)"
|
|
|
- if let cobRegex = try? NSRegularExpression(pattern: cobPattern),
|
|
|
- let cobMatch = cobRegex.firstMatch(in: reasonString, range: NSRange(location: 0, length: reasonString.utf16.count)) {
|
|
|
- let cobValueString = (reasonString as NSString).substring(with: cobMatch.range(at: 1))
|
|
|
- if let cobValue = Double(cobValueString) {
|
|
|
- let tempDict: [String: AnyObject] = ["COB": cobValue as AnyObject]
|
|
|
- if let fallbackCobMetric = CarbMetric(from: tempDict, key: "COB") {
|
|
|
- infoManager.updateInfoData(type: .cob, value: fallbackCobMetric)
|
|
|
- latestCOB = fallbackCobMetric
|
|
|
- } else {
|
|
|
- print("Failed to create CarbMetric from extracted COB value: \(cobValue)")
|
|
|
- }
|
|
|
+ // COB
|
|
|
+ if let cobMetric = CarbMetric(from: enactedOrSuggested, key: "COB") {
|
|
|
+ infoManager.updateInfoData(type: .cob, value: cobMetric)
|
|
|
+ latestCOB = cobMetric
|
|
|
+ } else if let reasonString = enactedOrSuggested["reason"] as? String {
|
|
|
+ // Fallback: Extract COB from reason string
|
|
|
+ let cobPattern = "COB: (\\d+(?:\\.\\d+)?)"
|
|
|
+ if let cobRegex = try? NSRegularExpression(pattern: cobPattern),
|
|
|
+ let cobMatch = cobRegex.firstMatch(in: reasonString, range: NSRange(location: 0, length: reasonString.utf16.count)) {
|
|
|
+ let cobValueString = (reasonString as NSString).substring(with: cobMatch.range(at: 1))
|
|
|
+ if let cobValue = Double(cobValueString) {
|
|
|
+ let tempDict: [String: AnyObject] = ["COB": cobValue as AnyObject]
|
|
|
+ if let fallbackCobMetric = CarbMetric(from: tempDict, key: "COB") {
|
|
|
+ infoManager.updateInfoData(type: .cob, value: fallbackCobMetric)
|
|
|
+ latestCOB = fallbackCobMetric
|
|
|
} else {
|
|
|
- print("Invalid COB value extracted from reason string: \(cobValueString)")
|
|
|
+ print("Failed to create CarbMetric from extracted COB value: \(cobValue)")
|
|
|
}
|
|
|
} else {
|
|
|
- print("COB pattern not found in reason string.")
|
|
|
+ print("Invalid COB value extracted from reason string: \(cobValueString)")
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- // Insulin Required
|
|
|
- if let insulinReqMetric = InsulinMetric(from: enactedOrSuggested, key: "insulinReq") {
|
|
|
- infoManager.updateInfoData(type: .recBolus, value: insulinReqMetric)
|
|
|
- UserDefaultsRepository.deviceRecBolus.value = insulinReqMetric.value
|
|
|
} else {
|
|
|
- UserDefaultsRepository.deviceRecBolus.value = 0
|
|
|
- }
|
|
|
-
|
|
|
- // Autosens
|
|
|
- if let sens = enactedOrSuggested["sensitivityRatio"] as? Double {
|
|
|
- let formattedSens = String(format: "%.0f", sens * 100.0) + "%"
|
|
|
- infoManager.updateInfoData(type: .autosens, value: formattedSens)
|
|
|
- }
|
|
|
-
|
|
|
- // Eventual BG
|
|
|
- if let eventualBGValue = enactedOrSuggested["eventualBG"] as? Double {
|
|
|
- let eventualBGQuantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: eventualBGValue)
|
|
|
- PredictionLabel.text = Localizer.formatQuantity(eventualBGQuantity)
|
|
|
+ print("COB pattern not found in reason string.")
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // Target
|
|
|
- let profileTargetHigh = profileManager.currentTargetHigh()
|
|
|
- var enactedTarget: HKQuantity?
|
|
|
- if let enactedTargetValue = enactedOrSuggested["current_target"] as? Double {
|
|
|
- var targetUnit = HKUnit.milligramsPerDeciliter
|
|
|
- if enactedTargetValue < 40 {
|
|
|
- targetUnit = .millimolesPerLiter
|
|
|
- }
|
|
|
- enactedTarget = HKQuantity(unit: targetUnit, doubleValue: enactedTargetValue)
|
|
|
- }
|
|
|
+ // Insulin Required
|
|
|
+ if let insulinReqMetric = InsulinMetric(from: enactedOrSuggested, key: "insulinReq") {
|
|
|
+ infoManager.updateInfoData(type: .recBolus, value: insulinReqMetric)
|
|
|
+ UserDefaultsRepository.deviceRecBolus.value = insulinReqMetric.value
|
|
|
+ } else {
|
|
|
+ UserDefaultsRepository.deviceRecBolus.value = 0
|
|
|
+ }
|
|
|
|
|
|
- if let profileTargetHigh = profileTargetHigh, let enactedTarget = enactedTarget {
|
|
|
- let profileTargetHighFormatted = Localizer.formatQuantity(profileTargetHigh)
|
|
|
- let enactedTargetFormatted = Localizer.formatQuantity(enactedTarget)
|
|
|
+ // Autosens
|
|
|
+ if let sens = enactedOrSuggested["sensitivityRatio"] as? Double {
|
|
|
+ let formattedSens = String(format: "%.0f", sens * 100.0) + "%"
|
|
|
+ infoManager.updateInfoData(type: .autosens, value: formattedSens)
|
|
|
+ }
|
|
|
|
|
|
- // Compare formatted values to avoid issues with minor floating-point differences
|
|
|
- // Profile target could be in another unit than enacted target
|
|
|
- if profileTargetHighFormatted != enactedTargetFormatted {
|
|
|
- infoManager.updateInfoData(type: .target, firstValue: profileTargetHigh, secondValue: enactedTarget, separator: .arrow)
|
|
|
- } else {
|
|
|
- infoManager.updateInfoData(type: .target, value: profileTargetHigh)
|
|
|
- }
|
|
|
- }
|
|
|
+ // Eventual BG
|
|
|
+ if let eventualBGValue = enactedOrSuggested["eventualBG"] as? Double {
|
|
|
+ let eventualBGQuantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: eventualBGValue)
|
|
|
+ PredictionLabel.text = Localizer.formatQuantity(eventualBGQuantity)
|
|
|
+ }
|
|
|
|
|
|
- // TDD
|
|
|
- if let tddMetric = InsulinMetric(from: enactedOrSuggested, key: "TDD") {
|
|
|
- infoManager.updateInfoData(type: .tdd, value: tddMetric)
|
|
|
+ // Target
|
|
|
+ let profileTargetHigh = profileManager.currentTargetHigh()
|
|
|
+ var enactedTarget: HKQuantity?
|
|
|
+ if let enactedTargetValue = enactedOrSuggested["current_target"] as? Double {
|
|
|
+ var targetUnit = HKUnit.milligramsPerDeciliter
|
|
|
+ if enactedTargetValue < 40 {
|
|
|
+ targetUnit = .millimolesPerLiter
|
|
|
}
|
|
|
+ enactedTarget = HKQuantity(unit: targetUnit, doubleValue: enactedTargetValue)
|
|
|
+ }
|
|
|
|
|
|
- let predictioncolor = UIColor.systemGray
|
|
|
- PredictionLabel.textColor = predictioncolor
|
|
|
- topPredictionBG = UserDefaultsRepository.minBGScale.value
|
|
|
- if let predbgdata = enactedOrSuggested["predBGs"] as? [String: AnyObject] {
|
|
|
- let predictionTypes: [(type: String, colorName: String, dataIndex: Int)] = [
|
|
|
- ("ZT", "ZT", 12),
|
|
|
- ("IOB", "Insulin", 13),
|
|
|
- ("COB", "LoopYellow", 14),
|
|
|
- ("UAM", "UAM", 15)
|
|
|
- ]
|
|
|
-
|
|
|
- var minPredBG = Double.infinity
|
|
|
- var maxPredBG = -Double.infinity
|
|
|
+ if let profileTargetHigh = profileTargetHigh, let enactedTarget = enactedTarget {
|
|
|
+ let profileTargetHighFormatted = Localizer.formatQuantity(profileTargetHigh)
|
|
|
+ let enactedTargetFormatted = Localizer.formatQuantity(enactedTarget)
|
|
|
|
|
|
- for (type, colorName, dataIndex) in predictionTypes {
|
|
|
- var predictionData = [ShareGlucoseData]()
|
|
|
- if let graphdata = predbgdata[type] as? [Double] {
|
|
|
- var predictionTime = lastLoopTime
|
|
|
- let toLoad = Int(UserDefaultsRepository.predictionToLoad.value * 12)
|
|
|
+ // Compare formatted values to avoid issues with minor floating-point differences
|
|
|
+ // Profile target could be in another unit than enacted target
|
|
|
+ if profileTargetHighFormatted != enactedTargetFormatted {
|
|
|
+ infoManager.updateInfoData(type: .target, firstValue: profileTargetHigh, secondValue: enactedTarget, separator: .arrow)
|
|
|
+ } else {
|
|
|
+ infoManager.updateInfoData(type: .target, value: profileTargetHigh)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- for i in 0...toLoad {
|
|
|
- if i < graphdata.count {
|
|
|
- let predictionValue = graphdata[i]
|
|
|
- minPredBG = min(minPredBG, predictionValue)
|
|
|
- maxPredBG = max(maxPredBG, predictionValue)
|
|
|
+ // TDD
|
|
|
+ if let tddMetric = InsulinMetric(from: enactedOrSuggested, key: "TDD") {
|
|
|
+ infoManager.updateInfoData(type: .tdd, value: tddMetric)
|
|
|
+ }
|
|
|
|
|
|
- let prediction = ShareGlucoseData(sgv: Int(round(predictionValue)), date: predictionTime, direction: "flat")
|
|
|
- predictionData.append(prediction)
|
|
|
- predictionTime += 300
|
|
|
- }
|
|
|
+ let predictioncolor = UIColor.systemGray
|
|
|
+ PredictionLabel.textColor = predictioncolor
|
|
|
+ topPredictionBG = UserDefaultsRepository.minBGScale.value
|
|
|
+ if let predbgdata = enactedOrSuggested["predBGs"] as? [String: AnyObject] {
|
|
|
+ let predictionTypes: [(type: String, colorName: String, dataIndex: Int)] = [
|
|
|
+ ("ZT", "ZT", 12),
|
|
|
+ ("IOB", "Insulin", 13),
|
|
|
+ ("COB", "LoopYellow", 14),
|
|
|
+ ("UAM", "UAM", 15)
|
|
|
+ ]
|
|
|
+
|
|
|
+ var minPredBG = Double.infinity
|
|
|
+ var maxPredBG = -Double.infinity
|
|
|
+
|
|
|
+ for (type, colorName, dataIndex) in predictionTypes {
|
|
|
+ var predictionData = [ShareGlucoseData]()
|
|
|
+ if let graphdata = predbgdata[type] as? [Double] {
|
|
|
+ var predictionTime = updatedTime ?? Date().timeIntervalSince1970
|
|
|
+ let toLoad = Int(UserDefaultsRepository.predictionToLoad.value * 12)
|
|
|
+
|
|
|
+ for i in 0...toLoad {
|
|
|
+ if i < graphdata.count {
|
|
|
+ let predictionValue = graphdata[i]
|
|
|
+ minPredBG = min(minPredBG, predictionValue)
|
|
|
+ maxPredBG = max(maxPredBG, predictionValue)
|
|
|
+
|
|
|
+ let prediction = ShareGlucoseData(sgv: Int(round(predictionValue)), date: predictionTime, direction: "flat")
|
|
|
+ predictionData.append(prediction)
|
|
|
+ predictionTime += 300
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- let color = UIColor(named: colorName) ?? UIColor.systemPurple
|
|
|
- updatePredictionGraphGeneric(
|
|
|
- dataIndex: dataIndex,
|
|
|
- predictionData: predictionData,
|
|
|
- chartLabel: type,
|
|
|
- color: color
|
|
|
- )
|
|
|
}
|
|
|
|
|
|
- if minPredBG != Double.infinity && maxPredBG != -Double.infinity {
|
|
|
- let value = "\(Localizer.toDisplayUnits(String(minPredBG)))/\(Localizer.toDisplayUnits(String(maxPredBG)))"
|
|
|
- infoManager.updateInfoData(type: .minMax, value: value)
|
|
|
- } else {
|
|
|
- infoManager.updateInfoData(type: .minMax, value: "N/A")
|
|
|
- }
|
|
|
+ let color = UIColor(named: colorName) ?? UIColor.systemPurple
|
|
|
+ updatePredictionGraphGeneric(
|
|
|
+ dataIndex: dataIndex,
|
|
|
+ predictionData: predictionData,
|
|
|
+ chartLabel: type,
|
|
|
+ color: color
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
- if let loopStatus = lastLoopRecord["recommendedTempBasal"] as? [String: AnyObject] {
|
|
|
- if let tempBasalTime = formatter.date(from: (loopStatus["timestamp"] as! String))?.timeIntervalSince1970 {
|
|
|
- var lastBGTime = lastLoopTime
|
|
|
- if bgData.count > 0 {
|
|
|
- lastBGTime = bgData[bgData.count - 1].date
|
|
|
- }
|
|
|
- if tempBasalTime > lastBGTime && !wasEnacted {
|
|
|
- LoopStatusLabel.text = "⏀"
|
|
|
- latestLoopStatusString = "⏀"
|
|
|
- } else {
|
|
|
- LoopStatusLabel.text = "↻"
|
|
|
- latestLoopStatusString = "↻"
|
|
|
- }
|
|
|
- }
|
|
|
+ if minPredBG != Double.infinity && maxPredBG != -Double.infinity {
|
|
|
+ let value = "\(Localizer.toDisplayUnits(String(minPredBG)))/\(Localizer.toDisplayUnits(String(maxPredBG)))"
|
|
|
+ infoManager.updateInfoData(type: .minMax, value: value)
|
|
|
} else {
|
|
|
- LoopStatusLabel.text = "↻"
|
|
|
- latestLoopStatusString = "↻"
|
|
|
+ infoManager.updateInfoData(type: .minMax, value: "N/A")
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- private func findFallbackEnactedAndSetLoopTime(
|
|
|
- in allDeviceStatuses: [[String: AnyObject]],
|
|
|
- formatter: ISO8601DateFormatter
|
|
|
- ) {
|
|
|
- for i in 1 ..< allDeviceStatuses.count {
|
|
|
- let ds = allDeviceStatuses[i]
|
|
|
- guard
|
|
|
- let openaps = ds["openaps"] as? [String: AnyObject],
|
|
|
- openaps["failureReason"] == nil,
|
|
|
- let enacted = openaps["enacted"] as? [String: AnyObject],
|
|
|
- let dateString = ds["created_at"] as? String,
|
|
|
- let dateTime = formatter.date(from: dateString)?.timeIntervalSince1970
|
|
|
- else {
|
|
|
- continue
|
|
|
+ if let loopStatus = lastLoopRecord["recommendedTempBasal"] as? [String: AnyObject] {
|
|
|
+ if let tempBasalTime = formatter.date(from: (loopStatus["timestamp"] as! String))?.timeIntervalSince1970 {
|
|
|
+ var lastBGTime = updatedTime ?? Date().timeIntervalSince1970
|
|
|
+ if bgData.count > 0 {
|
|
|
+ lastBGTime = bgData[bgData.count - 1].date
|
|
|
+ }
|
|
|
+ if tempBasalTime > lastBGTime && !wasEnacted {
|
|
|
+ LoopStatusLabel.text = "⏀"
|
|
|
+ latestLoopStatusString = "⏀"
|
|
|
+ } else {
|
|
|
+ LoopStatusLabel.text = "↻"
|
|
|
+ latestLoopStatusString = "↻"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ LoopStatusLabel.text = "↻"
|
|
|
+ latestLoopStatusString = "↻"
|
|
|
}
|
|
|
-
|
|
|
- UserDefaultsRepository.alertLastLoopTime.value = dateTime
|
|
|
- LogManager.shared.log(category: .deviceStatus, message: "Found older enacted. Setting lastLoopTime to \(dateTime)", isDebug: true)
|
|
|
-
|
|
|
- evaluateNotLooping(lastLoopTime: dateTime)
|
|
|
- return
|
|
|
}
|
|
|
-
|
|
|
- LogManager.shared.log(category: .deviceStatus, message: "No older record was enacted!")
|
|
|
}
|
|
|
}
|