Переглянути джерело

Merge branch 'dev' of github.com:nightscout/Trio-dev into stats-wip

Deniz Cengiz 1 рік тому
батько
коміт
9edf4188dc
31 змінених файлів з 46804 додано та 31789 видалено
  1. 0 1
      Model/Classes+Properties/OrefDetermination+CoreDataProperties.swift
  2. 0 1
      Model/TrioCoreDataPersistentContainer.xcdatamodeld/TrioCoreDataPersistentContainer.xcdatamodel/contents
  3. 12 0
      Trio.xcodeproj/project.pbxproj
  4. 1 1
      Trio/Resources/javascript/bundle/determine-basal.js
  5. 9 44
      Trio/Sources/APS/APSManager.swift
  6. 12 17
      Trio/Sources/APS/FetchGlucoseManager.swift
  7. 9 12
      Trio/Sources/APS/OpenAPS/OpenAPS.swift
  8. 0 2
      Trio/Sources/APS/Storage/DeterminationStorage.swift
  9. 1 1
      Trio/Sources/APS/Storage/TDDStorage.swift
  10. 29 0
      Trio/Sources/Helpers/BackgroundTask+Helper.swift
  11. 46303 31101
      Trio/Sources/Localizations/Main/Localizable.xcstrings
  12. 0 20
      Trio/Sources/Models/Determination.swift
  13. 4 0
      Trio/Sources/Models/Oref2_variables.swift
  14. 6 0
      Trio/Sources/Models/TDD.swift
  15. 52 0
      Trio/Sources/Modules/Home/HomeStateModel+Setup/CurrentTDDSetup.swift
  16. 10 0
      Trio/Sources/Modules/Home/HomeStateModel.swift
  17. 1 1
      Trio/Sources/Modules/Home/View/HomeRootView.swift
  18. 35 2
      Trio/Sources/Modules/Main/MainStateModel.swift
  19. 10 18
      Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift
  20. 25 10
      Trio/Sources/Services/LiveActivity/Data/DataManager.swift
  21. 3 16
      Trio/Sources/Shortcuts/LiveActivity/RestartLiveActivityIntentRequest.swift
  22. 15 2
      Trio/Sources/Shortcuts/Override/ApplyOverridePresetIntent.swift
  23. 11 8
      Trio/Sources/Shortcuts/Override/CancelOverrideIntent.swift
  24. 17 0
      Trio/Sources/Shortcuts/Override/OverridePresetEntity.swift
  25. 88 65
      Trio/Sources/Shortcuts/Override/OverridePresetsIntentRequest.swift
  26. 22 4
      Trio/Sources/Shortcuts/TempPresets/ApplyTempPresetIntent.swift
  27. 7 2
      Trio/Sources/Shortcuts/TempPresets/CancelTempPresetIntent.swift
  28. 23 0
      Trio/Sources/Shortcuts/TempPresets/TempPresetIntent.swift
  29. 94 92
      Trio/Sources/Shortcuts/TempPresets/TempPresetsIntentRequest.swift
  30. 3 1
      oref0_source_version.txt
  31. 2 368
      trio-oref/lib/determine-basal/determine-basal.js

+ 0 - 1
Model/Classes+Properties/OrefDetermination+CoreDataProperties.swift

@@ -37,7 +37,6 @@ public extension OrefDetermination {
     @NSManaged var threshold: NSDecimalNumber?
     @NSManaged var threshold: NSDecimalNumber?
     @NSManaged var timestamp: Date?
     @NSManaged var timestamp: Date?
     @NSManaged var timestampEnacted: Date?
     @NSManaged var timestampEnacted: Date?
-    @NSManaged var totalDailyDose: NSDecimalNumber?
     @NSManaged var forecasts: Set<Forecast>?
     @NSManaged var forecasts: Set<Forecast>?
 }
 }
 
 

+ 0 - 1
Model/TrioCoreDataPersistentContainer.xcdatamodeld/TrioCoreDataPersistentContainer.xcdatamodel/contents

@@ -138,7 +138,6 @@
         <attribute name="threshold" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <attribute name="threshold" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="timestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="timestampEnacted" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="timestampEnacted" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
-        <attribute name="totalDailyDose" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <relationship name="forecasts" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Forecast" inverseName="orefDetermination" inverseEntity="Forecast"/>
         <relationship name="forecasts" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Forecast" inverseName="orefDetermination" inverseEntity="Forecast"/>
         <fetchIndex name="byDate">
         <fetchIndex name="byDate">
             <fetchIndexElement property="deliverAt" type="Binary" order="descending"/>
             <fetchIndexElement property="deliverAt" type="Binary" order="descending"/>

+ 12 - 0
Trio.xcodeproj/project.pbxproj

@@ -204,6 +204,8 @@
 		38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; };
 		38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
+		49249B1C2D46E45E000F4866 /* CurrentTDDSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */; };
+		49249B382D46E76A000F4866 /* TDD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49249B372D46E76A000F4866 /* TDD.swift */; };
 		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
 		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
 		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
 		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
 		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
 		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
@@ -517,6 +519,7 @@
 		DD6B7CBB2C7FBBFA00B75029 /* ReviewInsulinActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */; };
 		DD6B7CBB2C7FBBFA00B75029 /* ReviewInsulinActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */; };
 		DD6D67E42C9C253500660C9B /* ColorSchemeOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */; };
 		DD6D67E42C9C253500660C9B /* ColorSchemeOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */; };
 		DD6F63CC2D27F615007D94CF /* TreatmentMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */; };
 		DD6F63CC2D27F615007D94CF /* TreatmentMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */; };
+		DD73FA0F2D74F58E00D19D1E /* BackgroundTask+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */; };
 		DD8262CB2D289297009F6F62 /* BolusConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */; };
 		DD8262CB2D289297009F6F62 /* BolusConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */; };
 		DD88C8E22C50420800F2D558 /* DefinitionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD88C8E12C50420800F2D558 /* DefinitionRow.swift */; };
 		DD88C8E22C50420800F2D558 /* DefinitionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD88C8E12C50420800F2D558 /* DefinitionRow.swift */; };
 		DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */; };
 		DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */; };
@@ -925,6 +928,8 @@
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
 		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
 		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
+		49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentTDDSetup.swift; sourceTree = "<group>"; };
+		49249B372D46E76A000F4866 /* TDD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD.swift; sourceTree = "<group>"; };
 		491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
@@ -1239,6 +1244,7 @@
 		DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewInsulinActionView.swift; sourceTree = "<group>"; };
 		DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewInsulinActionView.swift; sourceTree = "<group>"; };
 		DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeOption.swift; sourceTree = "<group>"; };
 		DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeOption.swift; sourceTree = "<group>"; };
 		DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentMenuView.swift; sourceTree = "<group>"; };
 		DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentMenuView.swift; sourceTree = "<group>"; };
+		DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BackgroundTask+Helper.swift"; sourceTree = "<group>"; };
 		DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusConfirmationView.swift; sourceTree = "<group>"; };
 		DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusConfirmationView.swift; sourceTree = "<group>"; };
 		DD88C8E12C50420800F2D558 /* DefinitionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefinitionRow.swift; sourceTree = "<group>"; };
 		DD88C8E12C50420800F2D558 /* DefinitionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefinitionRow.swift; sourceTree = "<group>"; };
 		DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseColorScheme.swift; sourceTree = "<group>"; };
 		DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseColorScheme.swift; sourceTree = "<group>"; };
@@ -2088,6 +2094,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				49249B372D46E76A000F4866 /* TDD.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
 				DD3078672D42F5CE00DE0490 /* WatchGlucoseObject.swift */,
 				DD3078672D42F5CE00DE0490 /* WatchGlucoseObject.swift */,
@@ -2152,6 +2159,7 @@
 			children = (
 			children = (
 				BD249DA62D42FE3800412DEB /* Calendar+GlucoseStatsChart.swift */,
 				BD249DA62D42FE3800412DEB /* Calendar+GlucoseStatsChart.swift */,
 				BD249DA42D42FD9500412DEB /* CustomDatePicker.swift */,
 				BD249DA42D42FD9500412DEB /* CustomDatePicker.swift */,
+				DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */,
 				CEF1ED6A2D58FB4600FAF41E /* CGMOptions.swift */,
 				CEF1ED6A2D58FB4600FAF41E /* CGMOptions.swift */,
 				C2A0A42E2CE0312C003B98E8 /* ConstantValues.swift */,
 				C2A0A42E2CE0312C003B98E8 /* ConstantValues.swift */,
 				DD940BAB2CA75889000830A5 /* DynamicGlucoseColor.swift */,
 				DD940BAB2CA75889000830A5 /* DynamicGlucoseColor.swift */,
@@ -2416,6 +2424,7 @@
 				58645B982CA2D1A4008AFCE7 /* GlucoseSetup.swift */,
 				58645B982CA2D1A4008AFCE7 /* GlucoseSetup.swift */,
 				58645B9A2CA2D24F008AFCE7 /* CarbSetup.swift */,
 				58645B9A2CA2D24F008AFCE7 /* CarbSetup.swift */,
 				58645B9C2CA2D275008AFCE7 /* DeterminationSetup.swift */,
 				58645B9C2CA2D275008AFCE7 /* DeterminationSetup.swift */,
+				49249B1B2D46E45E000F4866 /* CurrentTDDSetup.swift */,
 				58645B9E2CA2D2BE008AFCE7 /* PumpHistorySetup.swift */,
 				58645B9E2CA2D2BE008AFCE7 /* PumpHistorySetup.swift */,
 				58645BA02CA2D2F8008AFCE7 /* OverrideSetup.swift */,
 				58645BA02CA2D2F8008AFCE7 /* OverrideSetup.swift */,
 				58645BA22CA2D325008AFCE7 /* BatterySetup.swift */,
 				58645BA22CA2D325008AFCE7 /* BatterySetup.swift */,
@@ -3934,6 +3943,7 @@
 				1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */,
 				1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */,
 				CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */,
 				CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */,
 				38E4453A274E411700EC9A94 /* Disk+[UIImage].swift in Sources */,
 				38E4453A274E411700EC9A94 /* Disk+[UIImage].swift in Sources */,
+				DD73FA0F2D74F58E00D19D1E /* BackgroundTask+Helper.swift in Sources */,
 				72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */,
 				72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */,
 				E39E418C56A5A46B61D960EE /* ConfigEditorStateModel.swift in Sources */,
 				E39E418C56A5A46B61D960EE /* ConfigEditorStateModel.swift in Sources */,
 				45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */,
 				45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */,
@@ -4039,6 +4049,7 @@
 				38E44538274E411700EC9A94 /* Disk+[Data].swift in Sources */,
 				38E44538274E411700EC9A94 /* Disk+[Data].swift in Sources */,
 				98641AF4F92123DA668AB931 /* CarbRatioEditorRootView.swift in Sources */,
 				98641AF4F92123DA668AB931 /* CarbRatioEditorRootView.swift in Sources */,
 				BDF34F902C10CF8C00D51995 /* CoreDataStack.swift in Sources */,
 				BDF34F902C10CF8C00D51995 /* CoreDataStack.swift in Sources */,
+				49249B1C2D46E45E000F4866 /* CurrentTDDSetup.swift in Sources */,
 				CEE9A65C2BBB41C800EB5194 /* CalibrationService.swift in Sources */,
 				CEE9A65C2BBB41C800EB5194 /* CalibrationService.swift in Sources */,
 				110AEDED2C51A0AE00615CC9 /* ShortcutsConfigProvider.swift in Sources */,
 				110AEDED2C51A0AE00615CC9 /* ShortcutsConfigProvider.swift in Sources */,
 				38E4453D274E411700EC9A94 /* Disk+Errors.swift in Sources */,
 				38E4453D274E411700EC9A94 /* Disk+Errors.swift in Sources */,
@@ -4056,6 +4067,7 @@
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
 				1967DFBE29D052C200759F30 /* Icons.swift in Sources */,
 				1967DFBE29D052C200759F30 /* Icons.swift in Sources */,
 				DDD163182C4C694000CD525A /* AdjustmentsRootView.swift in Sources */,
 				DDD163182C4C694000CD525A /* AdjustmentsRootView.swift in Sources */,
+				49249B382D46E76A000F4866 /* TDD.swift in Sources */,
 				389ECE052601144100D86C4F /* ConcurrentMap.swift in Sources */,
 				389ECE052601144100D86C4F /* ConcurrentMap.swift in Sources */,
 				110AEDEC2C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift in Sources */,
 				110AEDEC2C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift in Sources */,
 				CE7CA3562A064973004BE681 /* StateIntentRequest.swift in Sources */,
 				CE7CA3562A064973004BE681 /* StateIntentRequest.swift in Sources */,

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
Trio/Resources/javascript/bundle/determine-basal.js


+ 9 - 44
Trio/Sources/APS/APSManager.swift

@@ -81,7 +81,7 @@ final class BaseAPSManager: APSManager, Injectable {
 
 
     private var lifetime = Lifetime()
     private var lifetime = Lifetime()
 
 
-    private var backGroundTaskID: UIBackgroundTaskIdentifier?
+    private var backgroundTaskID: UIBackgroundTaskIdentifier?
 
 
     var pumpManager: PumpManagerUI? {
     var pumpManager: PumpManagerUI? {
         get { deviceDataManager.pumpManager }
         get { deviceDataManager.pumpManager }
@@ -224,7 +224,7 @@ final class BaseAPSManager: APSManager, Injectable {
             // Cleanup background task
             // Cleanup background task
             if let backgroundTask = backgroundTask {
             if let backgroundTask = backgroundTask {
                 await UIApplication.shared.endBackgroundTask(backgroundTask)
                 await UIApplication.shared.endBackgroundTask(backgroundTask)
-                self.backGroundTaskID = .invalid
+                self.backgroundTaskID = .invalid
             }
             }
         }
         }
     }
     }
@@ -250,13 +250,13 @@ final class BaseAPSManager: APSManager, Injectable {
     private func setupLoop() async -> (LoopStats, UIBackgroundTaskIdentifier?) {
     private func setupLoop() async -> (LoopStats, UIBackgroundTaskIdentifier?) {
         // Start background task
         // Start background task
         let backgroundTask = await UIApplication.shared.beginBackgroundTask(withName: "Loop starting") { [weak self] in
         let backgroundTask = await UIApplication.shared.beginBackgroundTask(withName: "Loop starting") { [weak self] in
-            guard let self, let backgroundTask = self.backGroundTaskID else { return }
+            guard let self, let backgroundTask = self.backgroundTaskID else { return }
             Task {
             Task {
                 UIApplication.shared.endBackgroundTask(backgroundTask)
                 UIApplication.shared.endBackgroundTask(backgroundTask)
             }
             }
-            self.backGroundTaskID = .invalid
+            self.backgroundTaskID = .invalid
         }
         }
-        backGroundTaskID = backgroundTask
+        backgroundTaskID = backgroundTask
 
 
         // Set loop start time
         // Set loop start time
         lastLoopStartDate = Date()
         lastLoopStartDate = Date()
@@ -325,9 +325,9 @@ final class BaseAPSManager: APSManager, Injectable {
 
 
         if let error = error {
         if let error = error {
             warning(.apsManager, "Loop failed with error: \(error.localizedDescription)")
             warning(.apsManager, "Loop failed with error: \(error.localizedDescription)")
-            if let backgroundTask = backGroundTaskID {
+            if let backgroundTask = backgroundTaskID {
                 await UIApplication.shared.endBackgroundTask(backgroundTask)
                 await UIApplication.shared.endBackgroundTask(backgroundTask)
-                backGroundTaskID = .invalid
+                backgroundTaskID = .invalid
             }
             }
             processError(error)
             processError(error)
         } else {
         } else {
@@ -343,9 +343,9 @@ final class BaseAPSManager: APSManager, Injectable {
         }
         }
 
 
         // End of the BG tasks
         // End of the BG tasks
-        if let backgroundTask = backGroundTaskID {
+        if let backgroundTask = backgroundTaskID {
             await UIApplication.shared.endBackgroundTask(backgroundTask)
             await UIApplication.shared.endBackgroundTask(backgroundTask)
-            backGroundTaskID = .invalid
+            backgroundTaskID = .invalid
         }
         }
     }
     }
 
 
@@ -1117,41 +1117,6 @@ final class BaseAPSManager: APSManager, Injectable {
         }
         }
     }
     }
 
 
-    private func tddForStats() async -> (currentTDD: Decimal, tddTotalAverage: Decimal) {
-        let requestTDD = OrefDetermination.fetchRequest() as NSFetchRequest<NSFetchRequestResult>
-        let sort = NSSortDescriptor(key: "timestamp", ascending: false)
-        let daysOf14Ago = Date().addingTimeInterval(-14.days.timeInterval)
-        requestTDD.predicate = NSPredicate(format: "timestamp > %@", daysOf14Ago as NSDate)
-        requestTDD.sortDescriptors = [sort]
-        requestTDD.propertiesToFetch = ["timestamp", "totalDailyDose"]
-        requestTDD.resultType = .dictionaryResultType
-
-        var currentTDD: Decimal = 0
-        var tddTotalAverage: Decimal = 0
-
-        let results = await privateContext.perform {
-            do {
-                let fetchedResults = try self.privateContext.fetch(requestTDD) as? [[String: Any]]
-                return fetchedResults ?? []
-            } catch {
-                debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to get TDD Data for Statistics Upload")
-                return []
-            }
-        }
-
-        if !results.isEmpty {
-            if let latestTDD = results.first?["totalDailyDose"] as? NSDecimalNumber {
-                currentTDD = latestTDD.decimalValue
-            }
-            let tddArray = results.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }
-            if !tddArray.isEmpty {
-                tddTotalAverage = tddArray.reduce(0, +) / Decimal(tddArray.count)
-            }
-        }
-
-        return (currentTDD, tddTotalAverage)
-    }
-
     private func glucoseForStats() async -> (
     private func glucoseForStats() async -> (
         oneDayGlucose: (ifcc: Double, ngsp: Double, average: Double, median: Double, sd: Double, cv: Double, readings: Double),
         oneDayGlucose: (ifcc: Double, ngsp: Double, average: Double, median: Double, sd: Double, cv: Double, readings: Double),
         eA1cDisplayUnit: EstimatedA1cDisplayUnit,
         eA1cDisplayUnit: EstimatedA1cDisplayUnit,

+ 12 - 17
Trio/Sources/APS/FetchGlucoseManager.swift

@@ -248,29 +248,22 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
         var filteredByDate: [BloodGlucose] = []
         var filteredByDate: [BloodGlucose] = []
         var filtered: [BloodGlucose] = []
         var filtered: [BloodGlucose] = []
 
 
-        // start background time extension
-        var backGroundFetchBGTaskID: UIBackgroundTaskIdentifier?
-        backGroundFetchBGTaskID = await UIApplication.shared.beginBackgroundTask(withName: "save BG starting") {
-            guard let bg = backGroundFetchBGTaskID else { return }
-            UIApplication.shared.endBackgroundTask(bg)
-            backGroundFetchBGTaskID = .invalid
-        }
+        // Start background task
+        var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
+        backgroundTaskID = startBackgroundTask(withName: "Glucose Store and Heartbeat Decision")
 
 
-        defer {
-            if let backgroundTask = backGroundFetchBGTaskID {
-                Task {
-                    await UIApplication.shared.endBackgroundTask(backgroundTask)
-                }
-                backGroundFetchBGTaskID = .invalid
-            }
+        guard newGlucose.isNotEmpty else {
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "Glucose Store and Heartbeat Decision")
+            return
         }
         }
 
 
-        guard newGlucose.isNotEmpty else { return }
-
         filteredByDate = newGlucose.filter { $0.dateString > syncDate }
         filteredByDate = newGlucose.filter { $0.dateString > syncDate }
         filtered = glucoseStorage.filterTooFrequentGlucose(filteredByDate, at: syncDate)
         filtered = glucoseStorage.filterTooFrequentGlucose(filteredByDate, at: syncDate)
 
 
-        guard filtered.isNotEmpty else { return }
+        guard filtered.isNotEmpty else {
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "Glucose Store and Heartbeat Decision")
+            return
+        }
         debug(.deviceManager, "New glucose found")
         debug(.deviceManager, "New glucose found")
 
 
         // filter the data if it is the case
         // filter the data if it is the case
@@ -289,6 +282,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
 
 
         try await glucoseStorage.storeGlucose(filtered)
         try await glucoseStorage.storeGlucose(filtered)
         deviceDataManager.heartbeat(date: Date())
         deviceDataManager.heartbeat(date: Date())
+
+        endBackgroundTaskSafely(&backgroundTaskID, taskName: "Glucose Store and Heartbeat Decision")
     }
     }
 
 
     func sourceInfo() -> [String: Any]? {
     func sourceInfo() -> [String: Any]? {

+ 9 - 12
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -34,7 +34,6 @@ final class OpenAPS {
         await context.perform {
         await context.perform {
             let newOrefDetermination = OrefDetermination(context: self.context)
             let newOrefDetermination = OrefDetermination(context: self.context)
             newOrefDetermination.id = UUID()
             newOrefDetermination.id = UUID()
-            newOrefDetermination.totalDailyDose = self.decimalToNSDecimalNumber(determination.tdd)
             newOrefDetermination.insulinSensitivity = self.decimalToNSDecimalNumber(determination.isf)
             newOrefDetermination.insulinSensitivity = self.decimalToNSDecimalNumber(determination.isf)
             newOrefDetermination.currentTarget = self.decimalToNSDecimalNumber(determination.current_target)
             newOrefDetermination.currentTarget = self.decimalToNSDecimalNumber(determination.current_target)
             newOrefDetermination.eventualBG = determination.eventualBG.map(NSDecimalNumber.init)
             newOrefDetermination.eventualBG = determination.eventualBG.map(NSDecimalNumber.init)
@@ -55,9 +54,6 @@ final class OpenAPS {
             newOrefDetermination.expectedDelta = self.decimalToNSDecimalNumber(determination.expectedDelta)
             newOrefDetermination.expectedDelta = self.decimalToNSDecimalNumber(determination.expectedDelta)
             newOrefDetermination.cob = Int16(Int(determination.cob ?? 0))
             newOrefDetermination.cob = Int16(Int(determination.cob ?? 0))
             newOrefDetermination.manualBolusErrorString = self.decimalToNSDecimalNumber(determination.manualBolusErrorString)
             newOrefDetermination.manualBolusErrorString = self.decimalToNSDecimalNumber(determination.manualBolusErrorString)
-            newOrefDetermination.tempBasal = determination.insulin?.temp_basal.map { NSDecimalNumber(decimal: $0) }
-            newOrefDetermination.scheduledBasal = determination.insulin?.scheduled_basal.map { NSDecimalNumber(decimal: $0) }
-            newOrefDetermination.bolus = determination.insulin?.bolus.map { NSDecimalNumber(decimal: $0) }
             newOrefDetermination.smbToDeliver = determination.units.map { NSDecimalNumber(decimal: $0) }
             newOrefDetermination.smbToDeliver = determination.units.map { NSDecimalNumber(decimal: $0) }
             newOrefDetermination.carbsRequired = Int16(Int(determination.carbsReq ?? 0))
             newOrefDetermination.carbsRequired = Int16(Int(determination.carbsReq ?? 0))
             newOrefDetermination.isUploadedToNS = false
             newOrefDetermination.isUploadedToNS = false
@@ -392,16 +388,16 @@ final class OpenAPS {
             let overrideTargetBG = activeOverrides.first?.target?.decimalValue ?? 0
             let overrideTargetBG = activeOverrides.first?.target?.decimalValue ?? 0
 
 
             // Calculate averages for Total Daily Dose (TDD)
             // Calculate averages for Total Daily Dose (TDD)
-            let totalTDD = historicalTDDData.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }.reduce(0, +)
+            let totalTDD = historicalTDDData.compactMap { ($0["total"] as? NSDecimalNumber)?.decimalValue }.reduce(0, +)
             let totalDaysCount = max(historicalTDDData.count, 1)
             let totalDaysCount = max(historicalTDDData.count, 1)
 
 
             // Fetch recent TDD data for the past two hours
             // Fetch recent TDD data for the past two hours
-            let recentTDDData = historicalTDDData.filter { ($0["timestamp"] as? Date ?? Date()) >= twoHoursAgo }
+            let recentTDDData = historicalTDDData.filter { ($0["date"] as? Date ?? Date()) >= twoHoursAgo }
             let recentDataCount = max(recentTDDData.count, 1)
             let recentDataCount = max(recentTDDData.count, 1)
-            let recentTotalTDD = recentTDDData.compactMap { ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue }
+            let recentTotalTDD = recentTDDData.compactMap { ($0["total"] as? NSDecimalNumber)?.decimalValue }
                 .reduce(0, +)
                 .reduce(0, +)
 
 
-            let currentTDD = historicalTDDData.last?["totalDailyDose"] as? Decimal ?? 0
+            let currentTDD = historicalTDDData.last?["total"] as? Decimal ?? 0
             let averageTDDLastTwoHours = recentTotalTDD / Decimal(recentDataCount)
             let averageTDDLastTwoHours = recentTotalTDD / Decimal(recentDataCount)
             let averageTDDLastTenDays = totalTDD / Decimal(totalDaysCount)
             let averageTDDLastTenDays = totalTDD / Decimal(totalDaysCount)
             let weightedTDD = weightPercentage * averageTDDLastTwoHours + (1 - weightPercentage) * averageTDDLastTenDays
             let weightedTDD = weightPercentage * averageTDDLastTwoHours + (1 - weightPercentage) * averageTDDLastTenDays
@@ -410,6 +406,7 @@ final class OpenAPS {
             let oref2Data = Oref2_variables(
             let oref2Data = Oref2_variables(
                 average_total_data: currentTDD > 0 ? averageTDDLastTenDays : 0,
                 average_total_data: currentTDD > 0 ? averageTDDLastTenDays : 0,
                 weightedAverage: currentTDD > 0 ? weightedTDD : 1,
                 weightedAverage: currentTDD > 0 ? weightedTDD : 1,
+                currentTDD: currentTDD,
                 past2hoursAverage: currentTDD > 0 ? averageTDDLastTwoHours : 0,
                 past2hoursAverage: currentTDD > 0 ? averageTDDLastTwoHours : 0,
                 date: Date(),
                 date: Date(),
                 overridePercentage: overridePercentage,
                 overridePercentage: overridePercentage,
@@ -831,12 +828,12 @@ extension OpenAPS {
 
 
     func fetchHistoricalTDDData(from date: Date) throws -> [[String: Any]] {
     func fetchHistoricalTDDData(from date: Date) throws -> [[String: Any]] {
         try CoreDataStack.shared.fetchEntities(
         try CoreDataStack.shared.fetchEntities(
-            ofType: OrefDetermination.self,
+            ofType: TDDStored.self,
             onContext: context,
             onContext: context,
-            predicate: NSPredicate(format: "timestamp > %@ AND totalDailyDose > 0", date as NSDate),
-            key: "timestamp",
+            predicate: NSPredicate(format: "date > %@ AND total > 0", date as NSDate),
+            key: "date",
             ascending: true,
             ascending: true,
-            propertiesToFetch: ["timestamp", "totalDailyDose"]
+            propertiesToFetch: ["date", "total"]
         ) as? [[String: Any]] ?? []
         ) as? [[String: Any]] ?? []
     }
     }
 }
 }

+ 0 - 2
Trio/Sources/APS/Storage/DeterminationStorage.swift

@@ -182,8 +182,6 @@ final class BaseDeterminationStorage: DeterminationStorage, Injectable {
                         reservoir: self.decimal(from: orefDetermination.reservoir),
                         reservoir: self.decimal(from: orefDetermination.reservoir),
                         isf: self.decimal(from: orefDetermination.insulinSensitivity),
                         isf: self.decimal(from: orefDetermination.insulinSensitivity),
                         timestamp: orefDetermination.timestamp,
                         timestamp: orefDetermination.timestamp,
-                        tdd: self.decimal(from: orefDetermination.totalDailyDose),
-                        insulin: nil,
                         current_target: self.decimal(from: orefDetermination.currentTarget),
                         current_target: self.decimal(from: orefDetermination.currentTarget),
                         insulinForManualBolus: self.decimal(from: orefDetermination.insulinForManualBolus),
                         insulinForManualBolus: self.decimal(from: orefDetermination.insulinForManualBolus),
                         manualBolusErrorString: self.decimal(from: orefDetermination.manualBolusErrorString),
                         manualBolusErrorString: self.decimal(from: orefDetermination.manualBolusErrorString),

+ 1 - 1
Trio/Sources/APS/Storage/TDDStorage.swift

@@ -109,7 +109,7 @@ final class BaseTDDStorage: TDDStorage, Injectable {
         let bolusString = String(format: "%.2f", NSDecimalNumber(decimal: bolus.rounded(toPlaces: 2)).doubleValue)
         let bolusString = String(format: "%.2f", NSDecimalNumber(decimal: bolus.rounded(toPlaces: 2)).doubleValue)
         let tempBasalString = String(format: "%.2f", NSDecimalNumber(decimal: temp.rounded(toPlaces: 2)).doubleValue)
         let tempBasalString = String(format: "%.2f", NSDecimalNumber(decimal: temp.rounded(toPlaces: 2)).doubleValue)
         let scheduledBasalString = String(format: "%.2f", NSDecimalNumber(decimal: scheduled.rounded(toPlaces: 2)).doubleValue)
         let scheduledBasalString = String(format: "%.2f", NSDecimalNumber(decimal: scheduled.rounded(toPlaces: 2)).doubleValue)
-        let weightedAvgString = String(format: "%.2f", NSDecimalNumber(decimal: weighted?.rounded(toPlaces: 2) ?? 0))
+        let weightedAvgString = String(format: "%.2f", NSDecimalNumber(decimal: weighted?.rounded(toPlaces: 2) ?? 0).doubleValue)
         let hoursString = String(format: "%.5f", NSDecimalNumber(decimal: Decimal(hours).truncated(toPlaces: 5)).doubleValue)
         let hoursString = String(format: "%.5f", NSDecimalNumber(decimal: Decimal(hours).truncated(toPlaces: 5)).doubleValue)
 
 
         debug(.apsManager, """
         debug(.apsManager, """

+ 29 - 0
Trio/Sources/Helpers/BackgroundTask+Helper.swift

@@ -0,0 +1,29 @@
+import UIKit
+
+/// Ends a background task safely and ensures it is not called multiple times.
+///
+/// - Parameter taskID: The background task identifier to be ended.
+func endBackgroundTaskSafely(_ taskID: inout UIBackgroundTaskIdentifier, taskName: String = "Unnamed Task") {
+    if taskID != .invalid {
+        UIApplication.shared.endBackgroundTask(taskID)
+        debug(.default, "Background task '\(taskName)' ended successfully.")
+        taskID = .invalid
+    } else {
+        debug(.default, "Background task '\(taskName)' was already invalid or ended.")
+    }
+}
+
+/// Starts a background task and handles its expiration safely.
+///
+/// - Parameter name: The background task name.
+func startBackgroundTask(withName name: String) -> UIBackgroundTaskIdentifier {
+    var taskID = UIBackgroundTaskIdentifier.invalid
+
+    taskID = UIApplication.shared.beginBackgroundTask(withName: name) {
+        Task { @MainActor in
+            endBackgroundTaskSafely(&taskID, taskName: name)
+        }
+    }
+
+    return taskID
+}

Різницю між файлами не показано, бо вона завелика
+ 46303 - 31101
Trio/Sources/Localizations/Main/Localizable.xcstrings


+ 0 - 20
Trio/Sources/Models/Determination.swift

@@ -19,8 +19,6 @@ struct Determination: JSON, Equatable {
     let reservoir: Decimal?
     let reservoir: Decimal?
     var isf: Decimal?
     var isf: Decimal?
     var timestamp: Date?
     var timestamp: Date?
-    let tdd: Decimal?
-    let insulin: Insulin?
     var current_target: Decimal?
     var current_target: Decimal?
     let insulinForManualBolus: Decimal?
     let insulinForManualBolus: Decimal?
     let manualBolusErrorString: Decimal?
     let manualBolusErrorString: Decimal?
@@ -40,13 +38,6 @@ struct Predictions: JSON, Equatable {
     let uam: [Int]?
     let uam: [Int]?
 }
 }
 
 
-struct Insulin: JSON, Equatable {
-    let TDD: Decimal?
-    let bolus: Decimal?
-    let temp_basal: Decimal?
-    let scheduled_basal: Decimal?
-}
-
 extension Determination {
 extension Determination {
     private enum CodingKeys: String, CodingKey {
     private enum CodingKeys: String, CodingKey {
         case id
         case id
@@ -67,8 +58,6 @@ extension Determination {
         case reservoir
         case reservoir
         case timestamp
         case timestamp
         case isf = "ISF"
         case isf = "ISF"
-        case tdd = "TDD"
-        case insulin
         case current_target
         case current_target
         case insulinForManualBolus
         case insulinForManualBolus
         case manualBolusErrorString
         case manualBolusErrorString
@@ -91,15 +80,6 @@ extension Predictions {
     }
     }
 }
 }
 
 
-extension Insulin {
-    private enum CodingKeys: String, CodingKey {
-        case TDD
-        case bolus
-        case temp_basal
-        case scheduled_basal
-    }
-}
-
 protocol DeterminationObserver {
 protocol DeterminationObserver {
     func determinationDidUpdate(_ determination: Determination)
     func determinationDidUpdate(_ determination: Determination)
 }
 }

+ 4 - 0
Trio/Sources/Models/Oref2_variables.swift

@@ -2,6 +2,7 @@ import Foundation
 
 
 struct Oref2_variables: JSON, Equatable {
 struct Oref2_variables: JSON, Equatable {
     var average_total_data: Decimal
     var average_total_data: Decimal
+    var currentTDD: Decimal
     var weightedAverage: Decimal
     var weightedAverage: Decimal
     var past2hoursAverage: Decimal
     var past2hoursAverage: Decimal
     var date: Date
     var date: Date
@@ -24,6 +25,7 @@ struct Oref2_variables: JSON, Equatable {
     init(
     init(
         average_total_data: Decimal,
         average_total_data: Decimal,
         weightedAverage: Decimal,
         weightedAverage: Decimal,
+        currentTDD: Decimal,
         past2hoursAverage: Decimal,
         past2hoursAverage: Decimal,
         date: Date,
         date: Date,
         overridePercentage: Decimal,
         overridePercentage: Decimal,
@@ -44,6 +46,7 @@ struct Oref2_variables: JSON, Equatable {
     ) {
     ) {
         self.average_total_data = average_total_data
         self.average_total_data = average_total_data
         self.weightedAverage = weightedAverage
         self.weightedAverage = weightedAverage
+        self.currentTDD = currentTDD
         self.past2hoursAverage = past2hoursAverage
         self.past2hoursAverage = past2hoursAverage
         self.date = date
         self.date = date
         self.overridePercentage = overridePercentage
         self.overridePercentage = overridePercentage
@@ -68,6 +71,7 @@ extension Oref2_variables {
     private enum CodingKeys: String, CodingKey {
     private enum CodingKeys: String, CodingKey {
         case average_total_data
         case average_total_data
         case weightedAverage
         case weightedAverage
+        case currentTDD
         case past2hoursAverage
         case past2hoursAverage
         case date
         case date
         case overridePercentage
         case overridePercentage

+ 6 - 0
Trio/Sources/Models/TDD.swift

@@ -0,0 +1,6 @@
+import Foundation
+
+struct TDD: Codable, Equatable, Sendable {
+    let totalDailyDose: Decimal?
+    let timestamp: Date?
+}

+ 52 - 0
Trio/Sources/Modules/Home/HomeStateModel+Setup/CurrentTDDSetup.swift

@@ -0,0 +1,52 @@
+import CoreData
+import Foundation
+
+extension Home.StateModel {
+    func setupTDDArray() {
+        Task {
+            do {
+                // Get the NSManagedObjectIDs
+                let tddObjectIds = try await fetchTDDIDs()
+
+                // Get the NSManagedObjects and map them to TDD on the Main Thread
+                try await updateTDDArray(with: tddObjectIds, keyPath: \.fetchedTDDs)
+            } catch {
+                debug(.default, "\(DebuggingIdentifiers.failed) failed to fetch TDDs: \(error.localizedDescription)")
+            }
+        }
+    }
+
+    @MainActor private func updateTDDArray(
+        with IDs: [NSManagedObjectID],
+        keyPath: ReferenceWritableKeyPath<Home.StateModel, [TDD]>
+    ) async throws {
+        let tddObjects: [TDD] = try await CoreDataStack.shared
+            .getNSManagedObject(with: IDs, context: viewContext)
+            .compactMap { managedObject in
+                // Safely extract date and total as optional
+                let timestamp = managedObject.value(forKey: "date") as? Date
+                let totalDailyDose = (managedObject.value(forKey: "total") as? NSNumber)?.decimalValue
+                return TDD(totalDailyDose: totalDailyDose, timestamp: timestamp)
+            }
+        self[keyPath: keyPath] = tddObjects
+    }
+
+    private func fetchTDDIDs() async throws -> [NSManagedObjectID] {
+        let results = try await CoreDataStack.shared.fetchEntitiesAsync(
+            ofType: TDDStored.self,
+            onContext: tddFetchContext,
+            predicate: NSPredicate.predicateForOneDayAgo,
+            key: "date",
+            ascending: false,
+            fetchLimit: 1,
+            propertiesToFetch: ["total", "date", "objectID"]
+        )
+
+        return await tddFetchContext.perform {
+            guard let fetchedResults = results as? [[String: Any]] else {
+                return []
+            }
+            return fetchedResults.compactMap { $0["objectID"] as? NSManagedObjectID }
+        }
+    }
+}

+ 10 - 0
Trio/Sources/Modules/Home/HomeStateModel.swift

@@ -86,6 +86,7 @@ extension Home {
         var fpusFromPersistence: [CarbEntryStored] = []
         var fpusFromPersistence: [CarbEntryStored] = []
         var determinationsFromPersistence: [OrefDetermination] = []
         var determinationsFromPersistence: [OrefDetermination] = []
         var enactedAndNonEnactedDeterminations: [OrefDetermination] = []
         var enactedAndNonEnactedDeterminations: [OrefDetermination] = []
+        var fetchedTDDs: [TDD] = []
         var insulinFromPersistence: [PumpEventStored] = []
         var insulinFromPersistence: [PumpEventStored] = []
         var tempBasals: [PumpEventStored] = []
         var tempBasals: [PumpEventStored] = []
         var suspensions: [PumpEventStored] = []
         var suspensions: [PumpEventStored] = []
@@ -125,6 +126,7 @@ extension Home {
         let carbsFetchContext = CoreDataStack.shared.newTaskContext()
         let carbsFetchContext = CoreDataStack.shared.newTaskContext()
         let fpuFetchContext = CoreDataStack.shared.newTaskContext()
         let fpuFetchContext = CoreDataStack.shared.newTaskContext()
         let determinationFetchContext = CoreDataStack.shared.newTaskContext()
         let determinationFetchContext = CoreDataStack.shared.newTaskContext()
+        let tddFetchContext = CoreDataStack.shared.newTaskContext()
         let pumpHistoryFetchContext = CoreDataStack.shared.newTaskContext()
         let pumpHistoryFetchContext = CoreDataStack.shared.newTaskContext()
         let overrideFetchContext = CoreDataStack.shared.newTaskContext()
         let overrideFetchContext = CoreDataStack.shared.newTaskContext()
         let tempTargetFetchContext = CoreDataStack.shared.newTaskContext()
         let tempTargetFetchContext = CoreDataStack.shared.newTaskContext()
@@ -179,6 +181,9 @@ extension Home {
                         self.setupDeterminationsArray()
                         self.setupDeterminationsArray()
                     }
                     }
                     group.addTask {
                     group.addTask {
+                        self.setupTDDArray()
+                    }
+                    group.addTask {
                         self.setupInsulinArray()
                         self.setupInsulinArray()
                     }
                     }
                     group.addTask {
                     group.addTask {
@@ -237,6 +242,11 @@ extension Home {
                 self.setupDeterminationsArray()
                 self.setupDeterminationsArray()
             }.store(in: &subscriptions)
             }.store(in: &subscriptions)
 
 
+            coreDataPublisher?.filteredByEntityName("TDDStored").sink { [weak self] _ in
+                guard let self = self else { return }
+                self.setupTDDArray()
+            }.store(in: &subscriptions)
+
             coreDataPublisher?.filteredByEntityName("GlucoseStored").sink { [weak self] _ in
             coreDataPublisher?.filteredByEntityName("GlucoseStored").sink { [weak self] _ in
                 guard let self = self else { return }
                 guard let self = self else { return }
                 self.setupGlucoseArray()
                 self.setupGlucoseArray()

+ 1 - 1
Trio/Sources/Modules/Home/View/HomeRootView.swift

@@ -494,7 +494,7 @@ extension Home {
                         "TDD: " +
                         "TDD: " +
                             (
                             (
                                 Formatter.decimalFormatterWithTwoFractionDigits
                                 Formatter.decimalFormatterWithTwoFractionDigits
-                                    .string(from: (state.determinationsFromPersistence.first?.totalDailyDose ?? 0) as NSNumber) ??
+                                    .string(from: (state.fetchedTDDs.first?.totalDailyDose ?? 0) as NSNumber) ??
                                     "0"
                                     "0"
                             ) +
                             ) +
                             String(localized: " U", comment: "Insulin unit")
                             String(localized: " U", comment: "Insulin unit")

+ 35 - 2
Trio/Sources/Modules/Main/MainStateModel.swift

@@ -201,6 +201,37 @@ extension Main {
             SwiftMessages.show(config: config, view: view)
             SwiftMessages.show(config: config, view: view)
         }
         }
 
 
+        /*
+          Reclassification is needed for Medtronic pumps for 'Pump error:' RileyLink related messages.
+          For details, see https://discord.com/channels/1020905149037813862/1338245444186279946/1343469793013141525.
+          Reclassification of Info type messages is based on APSManager.APSError enum values.
+          Currently, we only re-classify APSError.pumpError 'Pump error:' type to MessageType.error.
+          MessageType.error messagges are always displayed to the user and the user cannot disable them.
+          Other APSManager.APSError remain as MessageType.info which allows users to disable them
+          using the 'Trio Notification' -> 'Always Notify Algorithm' setting.
+         */
+        func reclassifyInfoNotification(_ message: inout MessageContent) {
+            if message.title == "" {
+                switch message.type {
+                case .info:
+                    if let errorIndex = message.content.range(of: "error", options: .caseInsensitive) {
+                        message.title = String(localized: "Error", comment: "Error title")
+                        if let errorPumpIndex = message.content.range(of: "Pump error:", options: .caseInsensitive) {
+                            message.type = .error
+                        }
+                    } else {
+                        message.title = String(localized: "Info", comment: "Info title")
+                    }
+                case .warning:
+                    message.title = String(localized: "Warning", comment: "Warning title")
+                case .error:
+                    message.title = String(localized: "Error", comment: "Error title")
+                case .other:
+                    message.title = String(localized: "Info", comment: "Info title")
+                }
+            }
+        }
+
         override func subscribe() {
         override func subscribe() {
             router.mainModalScreen
             router.mainModalScreen
                 .map { $0?.modal(resolver: self.resolver!) }
                 .map { $0?.modal(resolver: self.resolver!) }
@@ -223,8 +254,10 @@ extension Main {
                 .receive(on: DispatchQueue.main)
                 .receive(on: DispatchQueue.main)
                 .sink { message in
                 .sink { message in
                     guard !self.isApnPumpConfigAction(message) else { return }
                     guard !self.isApnPumpConfigAction(message) else { return }
-                    guard self.router.allowNotify(message, self.settingsManager.settings) else { return }
-                    self.showAlertMessage(message)
+                    var reclassifyMessage = message
+                    self.reclassifyInfoNotification(&reclassifyMessage)
+                    guard self.router.allowNotify(reclassifyMessage, self.settingsManager.settings) else { return }
+                    self.showAlertMessage(reclassifyMessage)
                 }
                 }
                 .store(in: &lifetime)
                 .store(in: &lifetime)
 
 

+ 10 - 18
Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -727,14 +727,11 @@ extension Treatments.StateModel {
             let determinationObjects: [OrefDetermination] = try await CoreDataStack.shared
             let determinationObjects: [OrefDetermination] = try await CoreDataStack.shared
                 .getNSManagedObject(with: determinationObjectIDs, context: determinationFetchContext)
                 .getNSManagedObject(with: determinationObjectIDs, context: determinationFetchContext)
 
 
-            return await determinationFetchContext.perform {
-                guard let determinationObject = determinationObjects.first else {
-                    return nil
-                }
-
-                let eventualBG = determinationObject.eventualBG?.intValue
+            let determination = await determinationFetchContext.perform {
+                let determinationObject = determinationObjects.first
+                let eventualBG = determinationObject?.eventualBG?.intValue
 
 
-                let forecastsSet = determinationObject.forecasts ?? []
+                let forecastsSet = determinationObject?.forecasts ?? []
                 let predictions = Predictions(
                 let predictions = Predictions(
                     iob: forecastsSet.extractValues(for: "iob"),
                     iob: forecastsSet.extractValues(for: "iob"),
                     zt: forecastsSet.extractValues(for: "zt"),
                     zt: forecastsSet.extractValues(for: "zt"),
@@ -747,7 +744,6 @@ extension Treatments.StateModel {
                     reason: "",
                     reason: "",
                     units: 0,
                     units: 0,
                     insulinReq: 0,
                     insulinReq: 0,
-                    eventualBG: eventualBG,
                     sensitivityRatio: 0,
                     sensitivityRatio: 0,
                     rate: 0,
                     rate: 0,
                     duration: 0,
                     duration: 0,
@@ -756,23 +752,19 @@ extension Treatments.StateModel {
                     predictions: predictions.isEmpty ? nil : predictions,
                     predictions: predictions.isEmpty ? nil : predictions,
                     carbsReq: 0,
                     carbsReq: 0,
                     temp: nil,
                     temp: nil,
-                    bg: 0,
                     reservoir: 0,
                     reservoir: 0,
-                    isf: 0,
-                    tdd: 0,
-                    insulin: nil,
-                    current_target: 0,
                     insulinForManualBolus: 0,
                     insulinForManualBolus: 0,
                     manualBolusErrorString: 0,
                     manualBolusErrorString: 0,
-                    minDelta: 0,
-                    expectedDelta: 0,
-                    minGuardBG: 0,
-                    minPredBG: 0,
-                    threshold: 0,
                     carbRatio: 0,
                     carbRatio: 0,
                     received: false
                     received: false
                 )
                 )
             }
             }
+
+            guard !determinationObjects.isEmpty else {
+                return nil
+            }
+
+            return determination
         } catch {
         } catch {
             debug(
             debug(
                 .default,
                 .default,

+ 25 - 10
Trio/Sources/Services/LiveActivity/Data/DataManager.swift

@@ -25,6 +25,7 @@ extension LiveActivityManager {
         }
         }
     }
     }
 
 
+    // TODO: extract logic or at least rename function appropiately
     func fetchAndMapDetermination() async throws -> DeterminationData? {
     func fetchAndMapDetermination() async throws -> DeterminationData? {
         let results = try await CoreDataStack.shared.fetchEntitiesAsync(
         let results = try await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: OrefDetermination.self,
             ofType: OrefDetermination.self,
@@ -33,23 +34,37 @@ extension LiveActivityManager {
             key: "deliverAt",
             key: "deliverAt",
             ascending: false,
             ascending: false,
             fetchLimit: 1,
             fetchLimit: 1,
-            propertiesToFetch: ["iob", "cob", "totalDailyDose", "currentTarget", "deliverAt"]
+            propertiesToFetch: ["iob", "cob", "currentTarget", "deliverAt"]
+        )
+
+        let tddResults = try await CoreDataStack.shared.fetchEntitiesAsync(
+            ofType: TDDStored.self,
+            onContext: context,
+            predicate: NSPredicate.predicateFor30MinAgo,
+            key: "date",
+            ascending: false,
+            fetchLimit: 1,
+            propertiesToFetch: ["total"]
         )
         )
 
 
         return try await context.perform {
         return try await context.perform {
-            guard let determinationResults = results as? [[String: Any]] else {
+            guard let determinationResults = results as? [[String: Any]], let tddResults = tddResults as? [[String: Any]] else {
                 throw CoreDataError.fetchError(function: #function, file: #file)
                 throw CoreDataError.fetchError(function: #function, file: #file)
             }
             }
 
 
-            return determinationResults.first.map {
-                DeterminationData(
-                    cob: ($0["cob"] as? Int) ?? 0,
-                    iob: ($0["iob"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    tdd: ($0["totalDailyDose"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    target: ($0["currentTarget"] as? NSDecimalNumber)?.decimalValue ?? 0,
-                    date: $0["deliverAt"] as? Date ?? nil
-                )
+            guard let determination = determinationResults.first else {
+                return nil
             }
             }
+
+            let tddValue = (tddResults.first?["total"] as? NSDecimalNumber)?.decimalValue ?? 0
+
+            return DeterminationData(
+                cob: (determination["cob"] as? Int) ?? 0,
+                iob: (determination["iob"] as? NSDecimalNumber)?.decimalValue ?? 0,
+                tdd: tddValue,
+                target: (determination["currentTarget"] as? NSDecimalNumber)?.decimalValue ?? 0,
+                date: determination["deliverAt"] as? Date ?? nil
+            )
         }
         }
     }
     }
 
 

+ 3 - 16
Trio/Sources/Shortcuts/LiveActivity/RestartLiveActivityIntentRequest.swift

@@ -11,18 +11,9 @@ import UIKit
     /// - Throws: An error if the restart process fails.
     /// - Throws: An error if the restart process fails.
     /// - Returns: Void upon successful restart.
     /// - Returns: Void upon successful restart.
     @MainActor func performRestart() async throws {
     @MainActor func performRestart() async throws {
-        var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
-
         // Start background task
         // Start background task
-        backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Restart Live Activity") {
-            Task { @MainActor in
-                if backgroundTaskID != .invalid {
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                    backgroundTaskID = .invalid
-                    debug(.default, "Background task expired and ended.")
-                }
-            }
-        }
+        var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
+        backgroundTaskID = startBackgroundTask(withName: "Restart Live Activity")
 
 
         guard backgroundTaskID != .invalid else {
         guard backgroundTaskID != .invalid else {
             debug(.default, "Failed to start background task.")
             debug(.default, "Failed to start background task.")
@@ -34,10 +25,6 @@ import UIKit
         await liveActivityManager.restartActivityFromLiveActivityIntent()
         await liveActivityManager.restartActivityFromLiveActivityIntent()
 
 
         // Ensure background task ends properly
         // Ensure background task ends properly
-        if backgroundTaskID != .invalid {
-            UIApplication.shared.endBackgroundTask(backgroundTaskID)
-            debug(.default, "Background task ended successfully.")
-            backgroundTaskID = .invalid
-        }
+        endBackgroundTaskSafely(&backgroundTaskID, taskName: "Restart Live Activity")
     }
     }
 }
 }

+ 15 - 2
Trio/Sources/Shortcuts/Override/ApplyOverridePresetIntent.swift

@@ -1,24 +1,28 @@
 import AppIntents
 import AppIntents
 import Foundation
 import Foundation
 
 
+/// An App Intent that allows users to activate an override preset through the Shortcuts app.
 struct ApplyOverridePresetIntent: AppIntent {
 struct ApplyOverridePresetIntent: AppIntent {
-    // Title of the action in the Shortcuts app
+    /// The title displayed for this action in the Shortcuts app.
     static var title = LocalizedStringResource("Activate an override", table: "ShortcutsDetail")
     static var title = LocalizedStringResource("Activate an override", table: "ShortcutsDetail")
 
 
-    // Description of the action in the Shortcuts app
+    /// The description displayed for this action in the Shortcuts app.
     static var description = IntentDescription(.init("Activate an override", table: "ShortcutsDetail"))
     static var description = IntentDescription(.init("Activate an override", table: "ShortcutsDetail"))
 
 
+    /// The override preset to be applied.
     @Parameter(
     @Parameter(
         title: LocalizedStringResource("Override", table: "ShortcutsDetail"),
         title: LocalizedStringResource("Override", table: "ShortcutsDetail"),
         description: LocalizedStringResource("Override choice", table: "ShortcutsDetail")
         description: LocalizedStringResource("Override choice", table: "ShortcutsDetail")
     ) var preset: OverridePreset?
     ) var preset: OverridePreset?
 
 
+    /// A boolean parameter that determines whether confirmation is required before applying the override.
     @Parameter(
     @Parameter(
         title: LocalizedStringResource("Confirm Before applying", table: "ShortcutsDetail"),
         title: LocalizedStringResource("Confirm Before applying", table: "ShortcutsDetail"),
         description: LocalizedStringResource("If toggled, you will need to confirm before applying", table: "ShortcutsDetail"),
         description: LocalizedStringResource("If toggled, you will need to confirm before applying", table: "ShortcutsDetail"),
         default: true
         default: true
     ) var confirmBeforeApplying: Bool
     ) var confirmBeforeApplying: Bool
 
 
+    /// Defines the summary format shown in the Shortcuts app when configuring this intent.
     static var parameterSummary: some ParameterSummary {
     static var parameterSummary: some ParameterSummary {
         When(\ApplyOverridePresetIntent.$confirmBeforeApplying, .equalTo, true, {
         When(\ApplyOverridePresetIntent.$confirmBeforeApplying, .equalTo, true, {
             Summary("Applying \(\.$preset) override", table: "ShortcutsDetail") {
             Summary("Applying \(\.$preset) override", table: "ShortcutsDetail") {
@@ -31,12 +35,18 @@ struct ApplyOverridePresetIntent: AppIntent {
         })
         })
     }
     }
 
 
+    /// Executes the intent to apply the selected override preset.
+    ///
+    /// - Returns: A dialog indicating whether the override was successfully applied or failed.
+    /// - Throws: An error if an issue occurs during execution.
     @MainActor func perform() async throws -> some ProvidesDialog {
     @MainActor func perform() async throws -> some ProvidesDialog {
         do {
         do {
+            // Determine which preset to apply
             let presetToApply: OverridePreset
             let presetToApply: OverridePreset
             if let preset = preset {
             if let preset = preset {
                 presetToApply = preset
                 presetToApply = preset
             } else {
             } else {
+                // Request user selection if no preset is provided
                 presetToApply = try await $preset.requestDisambiguation(
                 presetToApply = try await $preset.requestDisambiguation(
                     among: await OverridePresetsIntentRequest().fetchAndProcessOverrides(),
                     among: await OverridePresetsIntentRequest().fetchAndProcessOverrides(),
                     dialog: IntentDialog(LocalizedStringResource("Select override", table: "ShortcutsDetail"))
                     dialog: IntentDialog(LocalizedStringResource("Select override", table: "ShortcutsDetail"))
@@ -44,6 +54,8 @@ struct ApplyOverridePresetIntent: AppIntent {
             }
             }
 
 
             let displayName: String = presetToApply.name
             let displayName: String = presetToApply.name
+
+            // Request confirmation before applying if required
             if confirmBeforeApplying {
             if confirmBeforeApplying {
                 try await requestConfirmation(
                 try await requestConfirmation(
                     result: .result(
                     result: .result(
@@ -55,6 +67,7 @@ struct ApplyOverridePresetIntent: AppIntent {
                 )
                 )
             }
             }
 
 
+            // Apply the override and return the appropriate dialog message
             if await OverridePresetsIntentRequest().enactOverride(presetToApply) {
             if await OverridePresetsIntentRequest().enactOverride(presetToApply) {
                 return .result(
                 return .result(
                     dialog: IntentDialog(
                     dialog: IntentDialog(

+ 11 - 8
Trio/Sources/Shortcuts/Override/CancelOverrideIntent.swift

@@ -1,19 +1,22 @@
 import AppIntents
 import AppIntents
 import Foundation
 import Foundation
 
 
+/// An App Intent that allows users to cancel an active override through the Shortcuts app.
 struct CancelOverrideIntent: AppIntent {
 struct CancelOverrideIntent: AppIntent {
-    // Title of the action in the Shortcuts app
+    /// The title displayed for this action in the Shortcuts app.
     static var title = LocalizedStringResource("Cancel override", table: "ShortcutsDetail")
     static var title = LocalizedStringResource("Cancel override", table: "ShortcutsDetail")
 
 
-    // Description of the action in the Shortcuts app
+    /// The description displayed for this action in the Shortcuts app.
     static var description = IntentDescription(.init("Cancel an active override", table: "ShortcutsDetail"))
     static var description = IntentDescription(.init("Cancel an active override", table: "ShortcutsDetail"))
 
 
+    /// Performs the intent action to cancel an active override.
+    ///
+    /// - Returns: A confirmation dialog indicating the override has been canceled.
+    /// - Throws: An error if the cancellation process fails.
     @MainActor func perform() async throws -> some ProvidesDialog {
     @MainActor func perform() async throws -> some ProvidesDialog {
-        do {
-            await OverridePresetsIntentRequest().cancelOverride()
-            return .result(
-                dialog: IntentDialog(LocalizedStringResource("Override canceled", table: "ShortcutsDetail"))
-            )
-        }
+        await OverridePresetsIntentRequest().cancelOverride()
+        return .result(
+            dialog: IntentDialog(LocalizedStringResource("Override canceled", table: "ShortcutsDetail"))
+        )
     }
     }
 }
 }

+ 17 - 0
Trio/Sources/Shortcuts/Override/OverridePresetEntity.swift

@@ -3,24 +3,41 @@ import Foundation
 import Intents
 import Intents
 import Swinject
 import Swinject
 
 
+/// Represents an override preset that can be used in the app.
 struct OverridePreset: AppEntity, Identifiable {
 struct OverridePreset: AppEntity, Identifiable {
+    /// Default query instance for fetching override presets.
     static var defaultQuery = OverridePresetsQuery()
     static var defaultQuery = OverridePresetsQuery()
 
 
+    /// Unique identifier for the override preset.
     var id: String
     var id: String
+
+    /// Name of the override preset.
     var name: String
     var name: String
 
 
+    /// Provides a display representation for the override preset.
     var displayRepresentation: DisplayRepresentation {
     var displayRepresentation: DisplayRepresentation {
         DisplayRepresentation(title: "\(name)")
         DisplayRepresentation(title: "\(name)")
     }
     }
 
 
+    /// Representation for the entity type when displayed in UI.
     static var typeDisplayRepresentation: TypeDisplayRepresentation = "Override"
     static var typeDisplayRepresentation: TypeDisplayRepresentation = "Override"
 }
 }
 
 
+/// Query structure for fetching override presets in an App Intent.
 struct OverridePresetsQuery: EntityQuery {
 struct OverridePresetsQuery: EntityQuery {
+    /// Fetches a list of override presets matching the given identifiers.
+    ///
+    /// - Parameter identifiers: A list of override preset IDs to fetch.
+    /// - Returns: An array of `OverridePreset` objects matching the given IDs.
+    /// - Throws: An error if the fetch operation fails.
     func entities(for identifiers: [OverridePreset.ID]) async throws -> [OverridePreset] {
     func entities(for identifiers: [OverridePreset.ID]) async throws -> [OverridePreset] {
         try await OverridePresetsIntentRequest().fetchIDs(identifiers)
         try await OverridePresetsIntentRequest().fetchIDs(identifiers)
     }
     }
 
 
+    /// Fetches a list of suggested override presets.
+    ///
+    /// - Returns: An array of available `OverridePreset` objects.
+    /// - Throws: An error if fetching fails.
     func suggestedEntities() async throws -> [OverridePreset] {
     func suggestedEntities() async throws -> [OverridePreset] {
         try await OverridePresetsIntentRequest().fetchAndProcessOverrides()
         try await OverridePresetsIntentRequest().fetchAndProcessOverrides()
     }
     }

+ 88 - 65
Trio/Sources/Shortcuts/Override/OverridePresetsIntentRequest.swift

@@ -9,6 +9,14 @@ import UIKit
         case noActiveOverride
         case noActiveOverride
     }
     }
 
 
+    private var intentSuccess: Bool = false
+
+    /**
+     Fetches and processes override presets from Core Data.
+
+     - Returns: An array of `OverridePreset` objects.
+     - Throws: An error if fetching fails or Core Data operations fail.
+     */
     func fetchAndProcessOverrides() async throws -> [OverridePreset] {
     func fetchAndProcessOverrides() async throws -> [OverridePreset] {
         do {
         do {
             // Fetch all Override Presets via OverrideStorage
             // Fetch all Override Presets via OverrideStorage
@@ -35,6 +43,13 @@ import UIKit
         }
         }
     }
     }
 
 
+    /**
+     Fetches override presets by their IDs.
+
+     - Parameter uuid: An array of `OverridePreset.ID` values to fetch.
+     - Returns: An array of `OverridePreset` objects matching the provided IDs.
+     - Throws: `overridePresetsError.noTempOverrideFound` if no presets are found.
+     */
     func fetchIDs(_ uuid: [OverridePreset.ID]) async throws -> [OverridePreset] {
     func fetchIDs(_ uuid: [OverridePreset.ID]) async throws -> [OverridePreset] {
         try await coredataContext.perform {
         try await coredataContext.perform {
             let fetchRequest: NSFetchRequest<OverrideStored> = OverrideStored.fetchRequest()
             let fetchRequest: NSFetchRequest<OverrideStored> = OverrideStored.fetchRequest()
@@ -64,6 +79,13 @@ import UIKit
         }
         }
     }
     }
 
 
+    /**
+     Fetches the Core Data `NSManagedObjectID` for a given `OverridePreset`.
+
+     - Parameter preset: The `OverridePreset` for which to fetch the object ID.
+     - Returns: The corresponding `NSManagedObjectID`.
+     - Throws: `overridePresetsError.noTempOverrideFound` if the preset is not found.
+     */
     private func fetchOverrideID(_ preset: OverridePreset) async throws -> NSManagedObjectID {
     private func fetchOverrideID(_ preset: OverridePreset) async throws -> NSManagedObjectID {
         let fetchRequest: NSFetchRequest<OverrideStored> = OverrideStored.fetchRequest()
         let fetchRequest: NSFetchRequest<OverrideStored> = OverrideStored.fetchRequest()
         fetchRequest.predicate = NSPredicate(format: "id == %@", preset.id)
         fetchRequest.predicate = NSPredicate(format: "id == %@", preset.id)
@@ -81,103 +103,96 @@ import UIKit
         }
         }
     }
     }
 
 
+    /**
+     Enacts an override preset by enabling it in Core Data and notifying the system.
+
+     - Parameter preset: The `OverridePreset` to enact.
+     - Returns: A boolean indicating whether the override was successfully enacted.
+     */
     @MainActor func enactOverride(_ preset: OverridePreset) async -> Bool {
     @MainActor func enactOverride(_ preset: OverridePreset) async -> Bool {
-        // Start background task
+        debug(.default, "Enacting override: \(preset.name)")
+        intentSuccess = false
+
         var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
         var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
-        backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Override Upload") {
-            guard backgroundTaskID != .invalid else { return }
-            Task {
-                UIApplication.shared.endBackgroundTask(backgroundTaskID)
-            }
-            backgroundTaskID = .invalid
-        }
+        backgroundTaskID = startBackgroundTask(withName: "Override Enact")
 
 
-        defer {
-            if backgroundTaskID != .invalid {
-                Task {
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
-        }
+        await disableAllActiveOverrides(shouldStartBackgroundTask: false)
 
 
         do {
         do {
-            // Get NSManagedObjectID of Preset
             let overrideID = try await fetchOverrideID(preset)
             let overrideID = try await fetchOverrideID(preset)
             guard let overrideObject = try viewContext.existingObject(with: overrideID) as? OverrideStored else {
             guard let overrideObject = try viewContext.existingObject(with: overrideID) as? OverrideStored else {
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Enact")
                 throw overridePresetsError.noTempOverrideFound
                 throw overridePresetsError.noTempOverrideFound
             }
             }
 
 
-            // Enable Override
             overrideObject.enabled = true
             overrideObject.enabled = true
             overrideObject.date = Date()
             overrideObject.date = Date()
             overrideObject.isUploadedToNS = false
             overrideObject.isUploadedToNS = false
 
 
-            // Disable previous overrides if necessary
-            await disableAllActiveOverrides(except: overrideID, createOverrideRunEntry: true, shouldStartBackgroundTask: false)
-
             if viewContext.hasChanges {
             if viewContext.hasChanges {
+                debug(.default, "Saving changes...")
                 try viewContext.save()
                 try viewContext.save()
+                debug(.default, "Waiting for notification...")
                 Foundation.NotificationCenter.default.post(name: .willUpdateOverrideConfiguration, object: nil)
                 Foundation.NotificationCenter.default.post(name: .willUpdateOverrideConfiguration, object: nil)
                 await awaitNotification(.didUpdateOverrideConfiguration)
                 await awaitNotification(.didUpdateOverrideConfiguration)
-                return true
+                debug(.default, "Notification received, continuing...")
+                intentSuccess = true
             }
             }
-            return false
+
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Enact")
+            debug(.default, "Finished. Override enacted via Shortcut.")
+            return intentSuccess
         } catch {
         } catch {
             debug(
             debug(
                 .default,
                 .default,
                 "\(DebuggingIdentifiers.failed) Failed to enact override: \(error.localizedDescription)"
                 "\(DebuggingIdentifiers.failed) Failed to enact override: \(error.localizedDescription)"
             )
             )
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Enact")
             return false
             return false
         }
         }
     }
     }
 
 
+    /**
+     Cancels all active overrides asynchronously.
+     */
     func cancelOverride() async {
     func cancelOverride() async {
-        await disableAllActiveOverrides(createOverrideRunEntry: true, shouldStartBackgroundTask: true)
+        await disableAllActiveOverrides(shouldStartBackgroundTask: true)
     }
     }
 
 
-    @MainActor func disableAllActiveOverrides(
-        except overrideID: NSManagedObjectID? = nil,
-        createOverrideRunEntry: Bool,
-        shouldStartBackgroundTask: Bool = true
-    ) async {
-        var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
+    /**
+     Disables all active overrides and optionally starts a background task.
 
 
-        if shouldStartBackgroundTask {
-            // Start background task
-            backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Override Cancel") {
-                guard backgroundTaskID != .invalid else { return }
-                Task {
-                    // End background task when the time is about to expire
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
-        }
+     - Parameter shouldStartBackgroundTask: A boolean indicating whether to start a background task.
+     */
+    @MainActor func disableAllActiveOverrides(shouldStartBackgroundTask: Bool) async {
+        debug(.default, "Disabling all active overrides")
+        var backgroundTaskID: UIBackgroundTaskIdentifier?
 
 
-        // Defer block to end background task when function exits, only if it was started
-        defer {
-            if shouldStartBackgroundTask, backgroundTaskID != .invalid {
-                Task {
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
+        if shouldStartBackgroundTask {
+            debug(.default, "Starting background task for override cancel")
+            backgroundTaskID = .invalid
+            backgroundTaskID = startBackgroundTask(withName: "Override Cancel")
         }
         }
 
 
         do {
         do {
             // Get NSManagedObjectID of all active overrides
             // Get NSManagedObjectID of all active overrides
-            let ids = try await overrideStorage.loadLatestOverrideConfigurations(fetchLimit: 0) // 0 = no fetch limit
-            // Fetch existing OverrideStored objects
+            let ids = try await overrideStorage.loadLatestOverrideConfigurations(fetchLimit: 0)
             let results = try ids.compactMap { id in
             let results = try ids.compactMap { id in
                 try self.viewContext.existingObject(with: id) as? OverrideStored
                 try self.viewContext.existingObject(with: id) as? OverrideStored
             }
             }
 
 
             // Return early if no results
             // Return early if no results
-            guard !results.isEmpty else { return }
+            guard !results.isEmpty else {
+                debug(.default, "No active overrides to cancel… returning early")
+                if var backgroundTaskID = backgroundTaskID {
+                    debug(.default, "Ending background task for override cancel")
+                    endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Cancel")
+                }
+                return
+            }
 
 
             // Create OverrideRunStored entry if needed
             // Create OverrideRunStored entry if needed
-            if createOverrideRunEntry, let canceledOverride = results.first {
+            if let canceledOverride = results.first {
                 let newOverrideRunStored = OverrideRunStored(context: viewContext)
                 let newOverrideRunStored = OverrideRunStored(context: viewContext)
                 newOverrideRunStored.id = UUID()
                 newOverrideRunStored.id = UUID()
                 newOverrideRunStored.name = canceledOverride.name
                 newOverrideRunStored.name = canceledOverride.name
@@ -190,30 +205,38 @@ import UIKit
                 newOverrideRunStored.isUploadedToNS = false
                 newOverrideRunStored.isUploadedToNS = false
             }
             }
 
 
-            // Disable all overrides except the one specified
+            // Disable all active overrides
             for overrideToCancel in results {
             for overrideToCancel in results {
-                if overrideToCancel.objectID != overrideID {
-                    overrideToCancel.enabled = false
-                    overrideToCancel.isUploadedToNS = false
-                }
+                let endTime = overrideToCancel.date?
+                    .addingTimeInterval(TimeInterval(truncating: overrideToCancel.duration ?? 0))
+
+                debugPrint(
+                    "Disabling override: \(overrideToCancel.name ?? "Unnamed") with end time: \(endTime?.description ?? "Unknown")"
+                )
+                overrideToCancel.enabled = false
+                overrideToCancel.isUploadedToNS = false
             }
             }
 
 
             if viewContext.hasChanges {
             if viewContext.hasChanges {
                 try viewContext.save()
                 try viewContext.save()
-
-                // Update State variables in OverrideView
+                debug(.default, "Waiting for notification...")
                 Foundation.NotificationCenter.default.post(name: .willUpdateOverrideConfiguration, object: nil)
                 Foundation.NotificationCenter.default.post(name: .willUpdateOverrideConfiguration, object: nil)
+                await awaitNotification(.didUpdateOverrideConfiguration)
+                debug(.default, "Notification received, continuing...")
             }
             }
 
 
-            // Await the notification
-            print("Waiting for notification...")
-            await awaitNotification(.didUpdateOverrideConfiguration)
-            print("Notification received, continuing...")
-
+            if var backgroundTaskID = backgroundTaskID {
+                debug(.default, "Ending background task for override cancel")
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Cancel")
+            }
         } catch {
         } catch {
             debugPrint(
             debugPrint(
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to disable active Overrides with error: \(error.localizedDescription)"
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to disable active Overrides with error: \(error.localizedDescription)"
             )
             )
+            if var backgroundTaskID = backgroundTaskID {
+                debug(.default, "Ending background task for override cancel")
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "Override Cancel")
+            }
         }
         }
     }
     }
 }
 }

+ 22 - 4
Trio/Sources/Shortcuts/TempPresets/ApplyTempPresetIntent.swift

@@ -1,21 +1,25 @@
 import AppIntents
 import AppIntents
 import Foundation
 import Foundation
 
 
+/// An App Intent that allows users to apply a temporary target preset through the Shortcuts app.
 struct ApplyTempPresetIntent: AppIntent {
 struct ApplyTempPresetIntent: AppIntent {
-    // Title of the action in the Shortcuts app
+    /// The title displayed for this action in the Shortcuts app.
     static var title: LocalizedStringResource = "Apply a Temporary Target"
     static var title: LocalizedStringResource = "Apply a Temporary Target"
 
 
-    // Description of the action in the Shortcuts app
+    /// The description displayed for this action in the Shortcuts app.
     static var description = IntentDescription("Enable a Temporary Target")
     static var description = IntentDescription("Enable a Temporary Target")
 
 
+    /// The temporary target preset to be applied.
     @Parameter(title: "Preset") var preset: TempPreset?
     @Parameter(title: "Preset") var preset: TempPreset?
 
 
+    /// A boolean parameter that determines whether confirmation is required before applying the temporary target.
     @Parameter(
     @Parameter(
         title: "Confirm Before applying",
         title: "Confirm Before applying",
         description: "If toggled, you will need to confirm before applying",
         description: "If toggled, you will need to confirm before applying",
         default: true
         default: true
     ) var confirmBeforeApplying: Bool
     ) var confirmBeforeApplying: Bool
 
 
+    /// Defines the summary format shown in the Shortcuts app when configuring this intent.
     static var parameterSummary: some ParameterSummary {
     static var parameterSummary: some ParameterSummary {
         When(\ApplyTempPresetIntent.$confirmBeforeApplying, .equalTo, true, {
         When(\ApplyTempPresetIntent.$confirmBeforeApplying, .equalTo, true, {
             Summary("Applying \(\.$preset)") {
             Summary("Applying \(\.$preset)") {
@@ -28,23 +32,34 @@ struct ApplyTempPresetIntent: AppIntent {
         })
         })
     }
     }
 
 
+    /// Converts a decimal duration value into a formatted time string.
+    ///
+    /// - Parameter decimal: The duration value in decimal format.
+    /// - Returns: A string representing the formatted time in hours and minutes.
     private func decimalToTimeFormattedString(decimal: Decimal) -> String {
     private func decimalToTimeFormattedString(decimal: Decimal) -> String {
-        let timeInterval = TimeInterval(decimal * 60) // seconds
+        let timeInterval = TimeInterval(decimal * 60) // Convert minutes to seconds
 
 
         let formatter = DateComponentsFormatter()
         let formatter = DateComponentsFormatter()
         formatter.allowedUnits = [.hour, .minute]
         formatter.allowedUnits = [.hour, .minute]
-        formatter.unitsStyle = .brief // example: 1h 10 min
+        formatter.unitsStyle = .brief // Example: "1h 10m"
 
 
         return formatter.string(from: timeInterval) ?? ""
         return formatter.string(from: timeInterval) ?? ""
     }
     }
 
 
+    /// Executes the intent to apply the selected temporary target preset.
+    ///
+    /// - Returns: A dialog indicating whether the temporary target was successfully applied or failed.
+    /// - Throws: An error if an issue occurs during execution.
     @MainActor func perform() async throws -> some ProvidesDialog {
     @MainActor func perform() async throws -> some ProvidesDialog {
         do {
         do {
             let intentRequest = TempPresetsIntentRequest()
             let intentRequest = TempPresetsIntentRequest()
             let presetToApply: TempPreset
             let presetToApply: TempPreset
+
+            // Determine which preset to apply
             if let preset = preset {
             if let preset = preset {
                 presetToApply = preset
                 presetToApply = preset
             } else {
             } else {
+                // Request user selection if no preset is provided
                 presetToApply = try await $preset.requestDisambiguation(
                 presetToApply = try await $preset.requestDisambiguation(
                     among: intentRequest.fetchAndProcessTempTargets(),
                     among: intentRequest.fetchAndProcessTempTargets(),
                     dialog: "Select Temporary Target"
                     dialog: "Select Temporary Target"
@@ -52,12 +67,15 @@ struct ApplyTempPresetIntent: AppIntent {
             }
             }
 
 
             let displayName: String = presetToApply.name
             let displayName: String = presetToApply.name
+
+            // Request confirmation before applying if required
             if confirmBeforeApplying {
             if confirmBeforeApplying {
                 try await requestConfirmation(
                 try await requestConfirmation(
                     result: .result(dialog: "Confirm to apply Temporary Target '\(displayName)'")
                     result: .result(dialog: "Confirm to apply Temporary Target '\(displayName)'")
                 )
                 )
             }
             }
 
 
+            // Apply the temporary target and return the appropriate dialog message
             if await intentRequest.enactTempTarget(presetToApply) {
             if await intentRequest.enactTempTarget(presetToApply) {
                 return .result(
                 return .result(
                     dialog: IntentDialog(
                     dialog: IntentDialog(

+ 7 - 2
Trio/Sources/Shortcuts/TempPresets/CancelTempPresetIntent.swift

@@ -1,13 +1,18 @@
 import AppIntents
 import AppIntents
 import Foundation
 import Foundation
 
 
+/// An App Intent that allows users to cancel an active temporary target through the Shortcuts app.
 struct CancelTempPresetIntent: AppIntent {
 struct CancelTempPresetIntent: AppIntent {
-    // Title of the action in the Shortcuts app
+    /// The title displayed for this action in the Shortcuts app.
     static var title: LocalizedStringResource = "Cancel a Temporary Target"
     static var title: LocalizedStringResource = "Cancel a Temporary Target"
 
 
-    // Description of the action in the Shortcuts app
+    /// The description displayed for this action in the Shortcuts app.
     static var description = IntentDescription("Cancel Temporary Target.")
     static var description = IntentDescription("Cancel Temporary Target.")
 
 
+    /// Performs the intent action to cancel an active temporary target.
+    ///
+    /// - Returns: A confirmation dialog indicating that the temporary target has been canceled.
+    /// - Throws: An error if the cancellation process fails.
     @MainActor func perform() async throws -> some ProvidesDialog {
     @MainActor func perform() async throws -> some ProvidesDialog {
         await TempPresetsIntentRequest().cancelTempTarget()
         await TempPresetsIntentRequest().cancelTempTarget()
         return .result(
         return .result(

+ 23 - 0
Trio/Sources/Shortcuts/TempPresets/TempPresetIntent.swift

@@ -3,27 +3,50 @@ import Foundation
 import Intents
 import Intents
 import Swinject
 import Swinject
 
 
+/// Represents a temporary target preset that can be used in the app.
 struct TempPreset: AppEntity, Identifiable {
 struct TempPreset: AppEntity, Identifiable {
+    /// Default query instance for fetching temporary presets.
     static var defaultQuery = TempPresetsQuery()
     static var defaultQuery = TempPresetsQuery()
 
 
+    /// Unique identifier for the temporary preset.
     var id: UUID
     var id: UUID
+
+    /// Name of the temporary preset.
     var name: String
     var name: String
+
+    /// The upper target value for the preset, if applicable.
     var targetTop: Decimal?
     var targetTop: Decimal?
+
+    /// The lower target value for the preset, if applicable.
     var targetBottom: Decimal?
     var targetBottom: Decimal?
+
+    /// The duration of the temporary preset in minutes.
     var duration: Decimal
     var duration: Decimal
 
 
+    /// Provides a display representation for the temporary preset.
     var displayRepresentation: DisplayRepresentation {
     var displayRepresentation: DisplayRepresentation {
         DisplayRepresentation(title: "\(name)")
         DisplayRepresentation(title: "\(name)")
     }
     }
 
 
+    /// Representation for the entity type when displayed in UI.
     static var typeDisplayRepresentation: TypeDisplayRepresentation = "Presets"
     static var typeDisplayRepresentation: TypeDisplayRepresentation = "Presets"
 }
 }
 
 
+/// Query structure for fetching temporary target presets in an App Intent.
 struct TempPresetsQuery: EntityQuery {
 struct TempPresetsQuery: EntityQuery {
+    /// Fetches a list of temporary target presets matching the given identifiers.
+    ///
+    /// - Parameter identifiers: A list of preset IDs to fetch.
+    /// - Returns: An array of `TempPreset` objects matching the given IDs.
+    /// - Throws: An error if the fetch operation fails.
     func entities(for identifiers: [TempPreset.ID]) async throws -> [TempPreset] {
     func entities(for identifiers: [TempPreset.ID]) async throws -> [TempPreset] {
         await TempPresetsIntentRequest().fetchIDs(identifiers)
         await TempPresetsIntentRequest().fetchIDs(identifiers)
     }
     }
 
 
+    /// Fetches a list of suggested temporary target presets.
+    ///
+    /// - Returns: An array of available `TempPreset` objects.
+    /// - Throws: An error if fetching fails.
     func suggestedEntities() async throws -> [TempPreset] {
     func suggestedEntities() async throws -> [TempPreset] {
         try await TempPresetsIntentRequest().fetchAndProcessTempTargets()
         try await TempPresetsIntentRequest().fetchAndProcessTempTargets()
     }
     }

+ 94 - 92
Trio/Sources/Shortcuts/TempPresets/TempPresetsIntentRequest.swift

@@ -2,12 +2,21 @@ import CoreData
 import Foundation
 import Foundation
 import UIKit
 import UIKit
 
 
+/// Handles intent requests related to temporary presets, such as fetching, enacting, and canceling temp targets.
 final class TempPresetsIntentRequest: BaseIntentsRequest {
 final class TempPresetsIntentRequest: BaseIntentsRequest {
+    /// Enum representing possible errors related to temporary presets.
     enum TempPresetsError: Error {
     enum TempPresetsError: Error {
         case noTempTargetFound
         case noTempTargetFound
         case noDurationDefined
         case noDurationDefined
     }
     }
 
 
+    /// Tracks whether the intent execution was successful.
+    private var intentSuccess: Bool = false
+
+    /// Fetches and processes all available temporary target presets.
+    ///
+    /// - Returns: An array of `TempPreset` objects.
+    /// - Throws: An error if fetching or processing fails.
     func fetchAndProcessTempTargets() async throws -> [TempPreset] {
     func fetchAndProcessTempTargets() async throws -> [TempPreset] {
         // Fetch all Temp Target Presets via TempTargetStorage
         // Fetch all Temp Target Presets via TempTargetStorage
         let allTempTargetPresetsIDs = try await tempTargetsStorage.fetchForTempTargetPresets()
         let allTempTargetPresetsIDs = try await tempTargetsStorage.fetchForTempTargetPresets()
@@ -38,6 +47,10 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
         }
         }
     }
     }
 
 
+    /// Fetches temporary target presets based on the given identifiers.
+    ///
+    /// - Parameter uuid: An array of preset IDs to fetch.
+    /// - Returns: An array of `TempPreset` objects.
     func fetchIDs(_ uuid: [TempPreset.ID]) async -> [TempPreset] {
     func fetchIDs(_ uuid: [TempPreset.ID]) async -> [TempPreset] {
         await coredataContext.perform {
         await coredataContext.perform {
             let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
             let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
@@ -67,6 +80,10 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
         }
         }
     }
     }
 
 
+    /// Fetches the `NSManagedObjectID` for a given `TempPreset`.
+    ///
+    /// - Parameter preset: The `TempPreset` to find.
+    /// - Returns: The `NSManagedObjectID` of the temp target if found, otherwise `nil`.
     private func fetchTempTargetID(_ preset: TempPreset) async -> NSManagedObjectID? {
     private func fetchTempTargetID(_ preset: TempPreset) async -> NSManagedObjectID? {
         let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
         let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
         fetchRequest.predicate = NSPredicate(format: "id == %@", preset.id.uuidString)
         fetchRequest.predicate = NSPredicate(format: "id == %@", preset.id.uuidString)
@@ -84,55 +101,43 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
         }
         }
     }
     }
 
 
+    /// Enacts a temporary target preset by updating Core Data and notifying relevant components.
+    ///
+    /// - Parameter preset: The `TempPreset` to apply.
+    /// - Returns: `true` if successfully enacted, otherwise `false`.
     @MainActor func enactTempTarget(_ preset: TempPreset) async -> Bool {
     @MainActor func enactTempTarget(_ preset: TempPreset) async -> Bool {
+        debug(.default, "Enacting Temp Target: \(preset.name)")
+        intentSuccess = false
+
         // Start background task
         // Start background task
         var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
         var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
-        backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "TempTarget Upload") {
-            guard backgroundTaskID != .invalid else { return }
-            Task {
-                // End background task when the time is about to expire
-                UIApplication.shared.endBackgroundTask(backgroundTaskID)
-            }
-            backgroundTaskID = .invalid
-        }
+        backgroundTaskID = startBackgroundTask(withName: "TempTarget Enact")
 
 
-        // Defer block to end background task when function exits
-        defer {
-            if backgroundTaskID != .invalid {
-                Task {
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
-        }
+        // Disable previous temp targets if necessary, without starting a background task
+        await disableAllActiveTempTargets(shouldStartBackgroundTask: false)
 
 
         do {
         do {
             // Get NSManagedObjectID of Preset
             // Get NSManagedObjectID of Preset
             guard let tempTargetID = await fetchTempTargetID(preset),
             guard let tempTargetID = await fetchTempTargetID(preset),
                   let tempTargetObject = try viewContext.existingObject(with: tempTargetID) as? TempTargetStored
                   let tempTargetObject = try viewContext.existingObject(with: tempTargetID) as? TempTargetStored
-            else { return false }
+            else {
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Enact")
+                throw TempPresetsError.noTempTargetFound
+            }
 
 
             // Enable TempTarget
             // Enable TempTarget
             tempTargetObject.enabled = true
             tempTargetObject.enabled = true
             tempTargetObject.date = Date()
             tempTargetObject.date = Date()
             tempTargetObject.isUploadedToNS = false
             tempTargetObject.isUploadedToNS = false
 
 
-            // Disable previous overrides if necessary, without starting a background task
-            await disableAllActiveTempTargets(
-                except: tempTargetID,
-                createTempTargetRunEntry: true,
-                shouldStartBackgroundTask: false
-            )
-
             if viewContext.hasChanges {
             if viewContext.hasChanges {
+                debug(.default, "Saving changes...")
                 try viewContext.save()
                 try viewContext.save()
-
+                debug(.default, "Waiting for notification...")
                 // Update State variables in TempTargetView
                 // Update State variables in TempTargetView
                 Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
                 Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
 
 
-                // Await the notification
-                print("Waiting for notification...")
-
+                // Prepare JSON for oref
                 guard let tempTargetDate = tempTargetObject.date, let tempTarget = tempTargetObject.target,
                 guard let tempTargetDate = tempTargetObject.date, let tempTarget = tempTargetObject.target,
                       let tempTargetDuration = tempTargetObject.duration else { return false }
                       let tempTargetDuration = tempTargetObject.duration else { return false }
 
 
@@ -148,108 +153,105 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
                     enabled: tempTargetObject.enabled,
                     enabled: tempTargetObject.enabled,
                     halfBasalTarget: tempTargetObject.halfBasalTarget as Decimal?
                     halfBasalTarget: tempTargetObject.halfBasalTarget as Decimal?
                 )
                 )
-
                 // Save the temp targets to JSON so that they get used by oref
                 // Save the temp targets to JSON so that they get used by oref
                 tempTargetsStorage.saveTempTargetsToStorage([tempTargetToStoreAsJSON])
                 tempTargetsStorage.saveTempTargetsToStorage([tempTargetToStoreAsJSON])
 
 
                 await awaitNotification(.didUpdateTempTargetConfiguration)
                 await awaitNotification(.didUpdateTempTargetConfiguration)
-                print("Notification received, continuing...")
 
 
-                return true
+                debug(.default, "Notification received, continuing...")
+                intentSuccess = true
             }
             }
+
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Enact")
+
+            debug(.default, "Finished. Temp Target enacted via Shortcut.")
+
+            return intentSuccess
         } catch {
         } catch {
-            // Handle error and ensure background task is ended
-            debugPrint("Failed to enact TempTarget: \(error.localizedDescription)")
-        }
+            debugPrint(
+                "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to enact Temp Target with error: \(error.localizedDescription)"
+            )
 
 
-        return false
+            endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Enact")
+
+            intentSuccess = false
+            return intentSuccess
+        }
     }
     }
 
 
+    /// Cancels an active temporary target.
     func cancelTempTarget() async {
     func cancelTempTarget() async {
-        await disableAllActiveTempTargets(createTempTargetRunEntry: true, shouldStartBackgroundTask: true)
+        await disableAllActiveTempTargets(shouldStartBackgroundTask: true)
         tempTargetsStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date().addingTimeInterval(-1))])
         tempTargetsStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date().addingTimeInterval(-1))])
     }
     }
 
 
-    @MainActor func disableAllActiveTempTargets(
-        except tempTargetID: NSManagedObjectID? = nil,
-        createTempTargetRunEntry: Bool,
-        shouldStartBackgroundTask: Bool = true
-    ) async {
-        var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
+    /// Disables all active temporary targets.
+    ///
+    /// - Parameter shouldStartBackgroundTask: A flag indicating whether a background task should be started.
+    @MainActor func disableAllActiveTempTargets(shouldStartBackgroundTask: Bool) async {
+        var backgroundTaskID: UIBackgroundTaskIdentifier?
 
 
         if shouldStartBackgroundTask {
         if shouldStartBackgroundTask {
-            // Start background task
-            backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "TempTarget Cancel") {
-                guard backgroundTaskID != .invalid else { return }
-                Task {
-                    // End background task when the time is about to expire
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
-        }
-
-        // Defer block to end background task when function exits, only if it was started
-        defer {
-            if shouldStartBackgroundTask, backgroundTaskID != .invalid {
-                Task {
-                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
-                }
-                backgroundTaskID = .invalid
-            }
+            debug(.default, "Starting background task for temp target cancel")
+            backgroundTaskID = .invalid
+            backgroundTaskID = startBackgroundTask(withName: "TempTarget Cancel")
         }
         }
 
 
         do {
         do {
-            // Get NSManagedObjectID of all active temp Targets
+            // Fetch active temp targets
             let ids = try await tempTargetsStorage.loadLatestTempTargetConfigurations(fetchLimit: 0)
             let ids = try await tempTargetsStorage.loadLatestTempTargetConfigurations(fetchLimit: 0)
-            // Fetch existing OverrideStored objects
             let results = try ids.compactMap { id in
             let results = try ids.compactMap { id in
                 try self.viewContext.existingObject(with: id) as? TempTargetStored
                 try self.viewContext.existingObject(with: id) as? TempTargetStored
             }
             }
 
 
-            // Return early if no results
-            guard !results.isEmpty else { return }
-
-            // Create TempTargetRunStored entry if needed
-            if createTempTargetRunEntry {
-                // Use the first temp target to create a new TempTargetRunStored entry
-                if let canceledTempTarget = results.first {
-                    let newTempTargetRunStored = TempTargetRunStored(context: viewContext)
-                    newTempTargetRunStored.id = UUID()
-                    newTempTargetRunStored.name = canceledTempTarget.name
-                    newTempTargetRunStored.startDate = canceledTempTarget.date ?? .distantPast
-                    newTempTargetRunStored.endDate = Date()
-                    newTempTargetRunStored
-                        .target = canceledTempTarget.target ?? 0
-                    newTempTargetRunStored.tempTarget = canceledTempTarget
-                    newTempTargetRunStored.isUploadedToNS = false
+            guard !results.isEmpty else {
+                debug(.default, "No active temp targets to cancel... returning early")
+
+                if var backgroundTaskID = backgroundTaskID {
+                    debug(.default, "Ending background task for temp target cancel")
+                    endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
                 }
                 }
+                return
+            }
+
+            // Create a new `TempTargetRunStored` entry
+            if let canceledTempTarget = results.first {
+                let newTempTargetRunStored = TempTargetRunStored(context: viewContext)
+                newTempTargetRunStored.id = UUID()
+                newTempTargetRunStored.name = canceledTempTarget.name
+                newTempTargetRunStored.startDate = canceledTempTarget.date ?? .distantPast
+                newTempTargetRunStored.endDate = Date()
+                newTempTargetRunStored.target = canceledTempTarget.target ?? 0
+                newTempTargetRunStored.tempTarget = canceledTempTarget
+                newTempTargetRunStored.isUploadedToNS = false
             }
             }
 
 
-            // Disable all override except the one with overrideID
+            // Disable all temp targets
             for tempTargetToCancel in results {
             for tempTargetToCancel in results {
-                if tempTargetToCancel.objectID != tempTargetID {
-                    tempTargetToCancel.enabled = false
-                    tempTargetToCancel.isUploadedToNS = false
-                }
+                tempTargetToCancel.enabled = false
+                tempTargetToCancel.isUploadedToNS = false
             }
             }
 
 
             if viewContext.hasChanges {
             if viewContext.hasChanges {
                 try viewContext.save()
                 try viewContext.save()
-
-                // Update State variables in OverrideView
+                debug(.default, "Waiting for notification...")
                 Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
                 Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
+                await awaitNotification(.didUpdateTempTargetConfiguration)
+                debug(.default, "Notification received, continuing...")
             }
             }
 
 
-            // Await the notification
-            print("Waiting for notification...")
-            await awaitNotification(.didUpdateTempTargetConfiguration)
-            print("Notification received, continuing...")
-
+            if var backgroundTaskID = backgroundTaskID {
+                debug(.default, "Ending background task for temp target cancel")
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
+            }
         } catch {
         } catch {
             debugPrint(
             debugPrint(
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to disable active Temp Targets with error: \(error.localizedDescription)"
                 "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to disable active Temp Targets with error: \(error.localizedDescription)"
             )
             )
+            if var backgroundTaskID = backgroundTaskID {
+                debug(.default, "Ending background task for temp target cancel")
+                endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
+            }
         }
         }
     }
     }
 }
 }

+ 3 - 1
oref0_source_version.txt

@@ -1,6 +1,8 @@
-oref0 branch: maxAbsorptionTime - git version: a542ed3
+oref0 branch: removeTDDCalc - git version: 73d6d6c
 
 
 Last commits:
 Last commits:
+73d6d6c webpack for Trio-dev
+5c6ce4b remove TDD calculation
 a542ed3 use guarded maxAbsorptionTime
 a542ed3 use guarded maxAbsorptionTime
 4c77757 Revert "reduce dynISF logging"
 4c77757 Revert "reduce dynISF logging"
 1567c76 use variable name maxMealAbsorptionTime
 1567c76 use variable name maxMealAbsorptionTime

+ 2 - 368
trio-oref/lib/determine-basal/determine-basal.js

@@ -154,9 +154,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     const isfAndCr = oref2_variables.isfAndCr;
     const isfAndCr = oref2_variables.isfAndCr;
     const isf = oref2_variables.isf;
     const isf = oref2_variables.isf;
     const cr_ = oref2_variables.cr;
     const cr_ = oref2_variables.cr;
-    const smbIsScheduledOff = oref2_variables.smbIsScheduledOff;
-    const start = oref2_variables.start;
-    var end = oref2_variables.end;
     const smbMinutes = oref2_variables.smbMinutes;
     const smbMinutes = oref2_variables.smbMinutes;
     const uamMinutes = oref2_variables.uamMinutes;
     const uamMinutes = oref2_variables.uamMinutes;
 
 
@@ -172,21 +169,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     }
     }
 
 
     // tdd past 24 hours
     // tdd past 24 hours
-    var pumpData = 0;
-    var logtdd = "";
-    var logBasal = "";
-    var logBolus = "";
-    var logTempBasal = "";
-    var dataLog = "";
     var logOutPut = "";
     var logOutPut = "";
     var tddReason = "";
     var tddReason = "";
-    var current = 0;
-    var tdd = 0;
-    var insulin = 0;
-    var tempInsulin = 0;
-    var bolusInsulin = 0;
-    var scheduledBasalInsulin = 0;
-    var quota = 0;
+    var tdd = oref2_variables.currentTDD;
+
     const weightedAverage = oref2_variables.weightedAverage;
     const weightedAverage = oref2_variables.weightedAverage;
     var overrideFactor = 1;
     var overrideFactor = 1;
     var sensitivity = profile.sens;
     var sensitivity = profile.sens;
@@ -204,55 +190,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     const weightPercentage = profile.weightPercentage;
     const weightPercentage = profile.weightPercentage;
     const average_total_data = oref2_variables.average_total_data;
     const average_total_data = oref2_variables.average_total_data;
 
 
-    function addTimeToDate(objDate, _hours) {
-        var ms = objDate.getTime();
-        var add_ms = _hours * 36e5;
-        var newDateObj = new Date(ms + add_ms);
-        return newDateObj;
-    }
-
-    function subtractTimeFromDate(date, hours_) {
-        var ms_ = date.getTime();
-        var add_ms_ = hours_ * 36e5;
-        var new_date = new Date(ms_ - add_ms_);
-        return new_date;
-    }
-
-    function accountForIncrements(insulin) {
-        // If you have not set this to.0.1 in Trio settings, this will be set to 0.05 (Omnipods) in code.
-        var minimalDose = profile.bolus_increment;
-        if (minimalDose != 0.1) {
-            minimalDose = 0.05;
-        }
-        var incrementsRaw = insulin / minimalDose;
-        if (incrementsRaw >= 1) {
-            var incrementsRounded = Math.floor(incrementsRaw);
-            return round(incrementsRounded * minimalDose, 5);
-        } else { return 0; }
-    }
-
-    function makeBaseString(base_timeStamp) {
-        function addZero(i) {
-            if (i < 10) { i = "0" + i }
-            return i;
-        }
-        let hour = addZero(base_timeStamp.getHours());
-        let minutes = addZero(base_timeStamp.getMinutes());
-        let seconds = "00";
-        let string = hour + ":" + minutes + ":" + seconds;
-        return string;
-    }
-
-    function timeDifferenceOfString(string1, string2) {
-        //Base time strings are in "00:00:00" format
-        var time1 = new Date("1/1/1999 " + string1);
-        var time2 = new Date("1/1/1999 " + string2);
-        var ms1 = time1.getTime();
-        var ms2 = time2.getTime();
-        var difference = (ms1 - ms2) / 36e5;
-        return difference;
-    }
-
     // In case the autosens.min/max limits are reversed:
     // In case the autosens.min/max limits are reversed:
     const minLimitChris = Math.min(profile.autosens_min, profile.autosens_max);
     const minLimitChris = Math.min(profile.autosens_min, profile.autosens_max);
     const maxLimitChris = Math.max(profile.autosens_min, profile.autosens_max);
     const maxLimitChris = Math.max(profile.autosens_min, profile.autosens_max);
@@ -263,306 +200,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
         console.log("Dynamic ISF disabled due to current autosens settings");
         console.log("Dynamic ISF disabled due to current autosens settings");
     }
     }
 
 
-    function calcScheduledBasalInsulin(lastRealTempTime, addedLastTempTime) {
-        var totalInsulin = 0;
-        var old = addedLastTempTime;
-        var totalDuration = (lastRealTempTime - addedLastTempTime) / 36e5;
-        var basDuration = 0;
-        var totalDurationCheck = totalDuration;
-        var durationCurrentSchedule = 0;
-
-        do {
-
-            if (totalDuration > 0) {
-
-                var baseTime_ = makeBaseString(old);
-
-                //Default basalrate in case none is found...
-                var basalScheduledRate_ = basalprofile[0].rate;
-                for (let m = 0; m < basalprofile.length; m++) {
-
-                    var timeToTest = basalprofile[m].start;
-
-                    if (baseTime_ == timeToTest) {
-
-                        if (m + 1 < basalprofile.length) {
-                            let end = basalprofile[m+1].start;
-                            let start = basalprofile[m].start;
-
-                            durationCurrentSchedule = timeDifferenceOfString(end, start);
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                        }
-                        else if (m + 1 == basalprofile.length) {
-                            let end = basalprofile[0].start;
-                            let start = basalprofile[m].start;
-                            // First schedule is 00:00:00. Changed places of start and end here.
-                            durationCurrentSchedule = 24 - (timeDifferenceOfString(start, end));
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                        }
-                        basalScheduledRate_ = basalprofile[m].rate;
-                        totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                        totalDuration -= basDuration;
-                        console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                        // Move clock to new date
-                        old = addTimeToDate(old, basDuration);
-                    }
-
-                    else if (baseTime_ > timeToTest) {
-
-                        if (m + 1 < basalprofile.length) {
-                            var timeToTest2 = basalprofile[m+1].start
-
-                            if (baseTime_ < timeToTest2) {
-
-                               //  durationCurrentSchedule = timeDifferenceOfString(end, start);
-                               durationCurrentSchedule = timeDifferenceOfString(timeToTest2, baseTime_);
-
-                                if (totalDuration >= durationCurrentSchedule) {
-                                    basDuration = durationCurrentSchedule;
-                                } else if (totalDuration < durationCurrentSchedule) {
-                                    basDuration = totalDuration;
-                                }
-
-                                basalScheduledRate_ = basalprofile[m].rate;
-                                totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                                totalDuration -= basDuration;
-                                console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                                // Move clock to new date
-                                old = addTimeToDate(old, basDuration);
-                            }
-                        }
-
-                        else if (m == basalprofile.length - 1) {
-                            // let start = basalprofile[m].start;
-                            let start = baseTime_;
-                            // First schedule is 00:00:00. Changed places of start and end here.
-                            durationCurrentSchedule = timeDifferenceOfString("23:59:59", start);
-
-                            if (totalDuration >= durationCurrentSchedule) {
-                                basDuration = durationCurrentSchedule;
-                            } else if (totalDuration < durationCurrentSchedule) {
-                                basDuration = totalDuration;
-                            }
-
-                            basalScheduledRate_ = basalprofile[m].rate;
-                            totalInsulin += accountForIncrements(basalScheduledRate_ * basDuration);
-                            totalDuration -= basDuration;
-                            console.log("Dynamic ratios log: scheduled insulin added: " + accountForIncrements(basalScheduledRate_ * basDuration) + " U. Bas duration: " + basDuration.toPrecision(3) + " h. Base Rate: " + basalScheduledRate_ + " U/h" + ". Time :" + baseTime_);
-                            // Move clock to new date
-                            old = addTimeToDate(old, basDuration);
-                        }
-                    }
-                }
-            }
-            //totalDurationCheck to avoid infinite loop
-        } while (totalDuration > 0 && totalDuration < totalDurationCheck);
-
-        // amount of insulin according to pump basal rate schedules
-        return totalInsulin;
-    }
-
-    // Check that there is enough pump history data (>21 hours) for tdd calculation. Estimate the missing hours (24-pumpData) using hours with scheduled basal rates. Not perfect, but sometimes the
-    // pump history in FAX is only 22-23.5 hours, even when you've been looping with FAX for many days. This is to reduce the error from just using pump history as data source as much as possible.
-    // AT basal rates are not used for this estimation, instead the basal rates in pump settings.
-
-    // Check for empty pump history (new FAX loopers). If empty: don't use dynamic settings!
-
-    if (!pumphistory.length) {
-        console.log("Pumphistory is empty!");
-        dynISFenabled = false;
-        enableDynamicCR = false;
-    } else {
-        let phLastEntry = pumphistory.length - 1;
-        var endDate = new Date(pumphistory[phLastEntry].timestamp);
-        var startDate = new Date(pumphistory[0].timestamp);
-
-        // If latest pump event is a temp basal
-        if (pumphistory[0]._type == "TempBasalDuration") {
-            startDate = new Date();
-        }
-        pumpData = (startDate - endDate) / 36e5;
-
-        if (pumpData < 23.9 && pumpData > 21) {
-            var missingHours = 24 - pumpData;
-            // Makes new end date for a total time duration of exakt 24 hour.
-            var endDate_ = subtractTimeFromDate(endDate, missingHours);
-            // endDate - endDate_ = missingHours
-            scheduledBasalInsulin = calcScheduledBasalInsulin(endDate, endDate_);
-            dataLog = "24 hours of data is required for an accurate tdd calculation. Currently only " + pumpData.toPrecision(3) + " hours of pump history data are available. Using your pump scheduled basals to fill in the missing hours. Scheduled basals added: " + scheduledBasalInsulin.toPrecision(5) + " U. ";
-        } else if (pumpData < 21) {
-            dynISFenabled = false;
-            enableDynamicCR = false;
-        } else {  dataLog = ""; }
-    }
-
-    // Calculate tdd ----------------------------------------------------------------------
-
-    //Bolus:
-    for (let i = 0; i < pumphistory.length; i++) {
-        if (pumphistory[i]._type == "Bolus") {
-            bolusInsulin += pumphistory[i].amount;
-        }
-    }
-
-    // Temp basals:
-    for (let j = 1; j < pumphistory.length; j++) {
-        if (pumphistory[j]._type == "TempBasal" && pumphistory[j].rate > 0) {
-            current = j;
-            quota = pumphistory[j].rate;
-            var duration = pumphistory[j-1]['duration (min)'] / 60;
-            var origDur = duration;
-            var pastTime = new Date(pumphistory[j-1].timestamp);
-            var morePresentTime = new Date(pastTime);
-            var substractTimeOfRewind = 0;
-            // If temp basal hasn't yet ended, use now as end date for calculation
-            do {
-                j--;
-                if (j == 0) {
-                    morePresentTime =  new Date();
-                    break;
-                }
-                else if (pumphistory[j]._type == "TempBasal" || pumphistory[j]._type == "PumpSuspend")  {
-                    morePresentTime = new Date(pumphistory[j].timestamp);
-                    break;
-                }
-                // During the time the Medtronic pumps are rewinded and primed, this duration of suspened insulin delivery needs to be accounted for.
-                var pp = j-2;
-                if (pp >= 0) {
-                    if (pumphistory[pp]._type == "Rewind") {
-                        let rewindTimestamp = pumphistory[pp].timestamp;
-                        // There can be several Prime events
-                        while (pp - 1 >= 0) {
-                            pp -= 1;
-                            if (pumphistory[pp]._type == "Prime") {
-                                substractTimeOfRewind = (pumphistory[pp].timestamp - rewindTimestamp) / 36e5;
-                            } else { break }
-                        }
-
-                        // If Medtronic user forgets to insert infusion set
-                        if (substractTimeOfRewind >= duration) {
-                            morePresentTime = new Date(rewindTimestamp);
-                            substractTimeOfRewind = 0;
-                        }
-                    }
-                }
-            } while (j > 0);
-
-            var diff = (morePresentTime - pastTime) / 36e5;
-            if (diff < origDur) {
-                duration = diff;
-            }
-
-            insulin = quota * (duration - substractTimeOfRewind);
-            tempInsulin += accountForIncrements(insulin);
-            j = current;
-        }
-    }
-    //  Check and count for when basals are delivered with a scheduled basal rate.
-    //  1. Check for 0 temp basals with 0 min duration. This is for when ending a manual temp basal and (perhaps) continuing in open loop for a while.
-    //  2. Check for temp basals that completes. This is for when disconnected from link/iphone, or when in open loop.
-    //  3. Account for a punp suspension. This is for when pod screams or when MDT or pod is manually suspended.
-    //  4. Account for a pump resume (in case pump/cgm is disconnected before next loop).
-    //  To do: are there more circumstances when scheduled basal rates are used? Do we need to care about "Prime" and "Rewind" with MDT pumps?
-    //
-    for (let k = 0; k < pumphistory.length; k++) {
-        // Check for 0 temp basals with 0 min duration.
-        insulin = 0;
-        if (pumphistory[k]['duration (min)'] == 0 || pumphistory[k]._type == "PumpResume") {
-            let time1 = new Date(pumphistory[k].timestamp);
-            let time2 = new Date(time1);
-            let l = k;
-            do {
-                if (l > 0) {
-                    --l;
-                    if (pumphistory[l]._type == "TempBasal") {
-                        time2 = new Date(pumphistory[l].timestamp);
-                        break;
-                    }
-                }
-            } while (l > 0);
-            // duration of current scheduled basal in h
-            let basDuration = (time2 - time1) / 36e5;
-
-            if (basDuration > 0) {
-                scheduledBasalInsulin += calcScheduledBasalInsulin(time2, time1);
-            }
-        }
-    }
-
-    // Check for temp basals that completes
-    for (let n = pumphistory.length -1; n > 0; n--) {
-        if (pumphistory[n]._type == "TempBasalDuration") {
-            // duration in hours
-            let oldBasalDuration = pumphistory[n]['duration (min)'] / 60;
-            // time of old temp basal
-            let oldTime = new Date(pumphistory[n].timestamp);
-            var newTime = new Date(oldTime);
-            let o = n;
-            do {
-                --o;
-                if (o >= 0) {
-                    if (pumphistory[o]._type == "TempBasal" || pumphistory[o]._type == "PumpSuspend") {
-                        // time of next (new) temp basal or a pump suspension
-                        newTime = new Date(pumphistory[o].timestamp);
-                        break;
-                    }
-                }
-            } while (o > 0);
-
-            // When latest temp basal is index 0 in pump history
-            if (n == 0 && pumphistory[0]._type == "TempBasalDuration") {
-                newTime = new Date();
-                oldBasalDuration = pumphistory[n]['duration (min)'] / 60;
-            }
-
-            let tempBasalTimeDifference = (newTime - oldTime) / 36e5;
-            let timeOfbasal = tempBasalTimeDifference - oldBasalDuration;
-            // if duration of scheduled basal is more than 0
-            if (timeOfbasal > 0) {
-                // Timestamp after completed temp basal
-                let timeOfScheduledBasal =  addTimeToDate(oldTime, oldBasalDuration);
-                scheduledBasalInsulin += calcScheduledBasalInsulin(newTime, timeOfScheduledBasal);
-            }
-        }
-    }
-
-    tdd = bolusInsulin + tempInsulin + scheduledBasalInsulin;
-
-
-    var insulin_ = {
-        TDD: round(tdd, 5),
-        bolus: round(bolusInsulin, 5),
-        temp_basal: round(tempInsulin, 5),
-        scheduled_basal: round(scheduledBasalInsulin, 5)
-    }
-
-    if (pumpData > 21) {
-        logBolus = ". Bolus insulin: " + bolusInsulin.toPrecision(5) + " U";
-        logTempBasal = ". Temporary basal insulin: " + tempInsulin.toPrecision(5) + " U";
-        logBasal = ". Insulin with scheduled basal rate: " + scheduledBasalInsulin.toPrecision(5) + " U";
-        logtdd = " TDD past 24h is: " + tdd.toPrecision(5) + " U";
-        logOutPut = dataLog + logtdd + logBolus + logTempBasal + logBasal;
-
-        tddReason = ", TDD: " + round(tdd,2) + " U, " + round(bolusInsulin/tdd*100,0) + "% Bolus " + round((tempInsulin+scheduledBasalInsulin)/tdd*100,0) +  "% Basal";
-
-    } else { tddReason = ", TDD: Not enough pumpData (< 21h)"; }
-
-    var tdd_before = tdd;
-
-    // -------------------- END OF TDD ----------------------------------------------------
-
     // Dynamic ratios
     // Dynamic ratios
     const BG = glucose_status.glucose;
     const BG = glucose_status.glucose;
     const useDynamicCR = preferences.enableDynamicCR;
     const useDynamicCR = preferences.enableDynamicCR;
@@ -1136,8 +773,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
         , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
         , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered
         , 'sensitivityRatio' : sensitivityRatio
         , 'sensitivityRatio' : sensitivityRatio
         , 'CR' : round(carbRatio, 1)
         , 'CR' : round(carbRatio, 1)
-        , 'TDD': tdd_before
-        , 'insulin': insulin_
         , 'current_target': target_bg
         , 'current_target': target_bg
         , 'insulinForManualBolus': insulinForManualBolus
         , 'insulinForManualBolus': insulinForManualBolus
         , 'manualBolusErrorString': manualBolusErrorString
         , 'manualBolusErrorString': manualBolusErrorString
@@ -1553,7 +1188,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
     rT.ISF=convert_bg(sens, profile);
     rT.ISF=convert_bg(sens, profile);
     rT.CR=round(carbRatio, 1);
     rT.CR=round(carbRatio, 1);
     rT.target_bg=convert_bg(target_bg, profile);
     rT.target_bg=convert_bg(target_bg, profile);
-    rT.TDD=round(tdd_before, 2);
     rT.current_target=round(target_bg, 0);
     rT.current_target=round(target_bg, 0);
 
 
     var cr_log = rT.CR;
     var cr_log = rT.CR;