Jelajahi Sumber

[Part 6 of 6] Remove OpenAPSSwift.swift and use native arguments

This commit is the last part of our removal of the JSON conversion we
used to do when we ran the oref algorithm using Javascript. In this
commit, we remove the OpenAPSSwift file and just call the underlying
algorithm functions directly from OpenAPS.

One change in functionality is that we expose raw DeterminationError
messages instead of catching them and converting them to APSError
exceptions with a generic "No determination error" error
message. These exception messages will be user visible when they
happen.
Sam King 2 hari lalu
induk
melakukan
991dff1b15

+ 0 - 8
Trio.xcodeproj/project.pbxproj

@@ -256,7 +256,6 @@
 		3B506FD92E635304000740B9 /* IOBService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B506FD82E635304000740B9 /* IOBService.swift */; };
 		3B506FD92E635304000740B9 /* IOBService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B506FD82E635304000740B9 /* IOBService.swift */; };
 		3B56079E2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B56079D2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift */; };
 		3B56079E2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B56079D2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift */; };
 		3B5607A02ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B56079F2ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift */; };
 		3B5607A02ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B56079F2ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift */; };
-		3B5CD1EC2D4912A600CE213C /* OpenAPSSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD1E92D4912A600CE213C /* OpenAPSSwift.swift */; };
 		3B5CD1ED2D4912A600CE213C /* JSONBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */; };
 		3B5CD1ED2D4912A600CE213C /* JSONBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */; };
 		3B5CD2982D4AEA3C00CE213C /* Carbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD2922D4AEA3C00CE213C /* Carbs.swift */; };
 		3B5CD2982D4AEA3C00CE213C /* Carbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD2922D4AEA3C00CE213C /* Carbs.swift */; };
 		3B5CD2992D4AEA3C00CE213C /* Isf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD2932D4AEA3C00CE213C /* Isf.swift */; };
 		3B5CD2992D4AEA3C00CE213C /* Isf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD2932D4AEA3C00CE213C /* Isf.swift */; };
@@ -300,7 +299,6 @@
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BE2F1E82E030E2F009E2900 /* MealCobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */; };
 		3BE2F1E82E030E2F009E2900 /* MealCobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */; };
 		3BE2F1EA2E031951009E2900 /* MealCobBucketingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */; };
 		3BE2F1EA2E031951009E2900 /* MealCobBucketingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */; };
-		3BEA3AE02D58F79700A67A1D /* OrefFunctionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEA3ADE2D58F79700A67A1D /* OrefFunctionResult.swift */; };
 		3BEDC9932EEB27B600AC6492 /* IobConsecutiveEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEDC9922EEB27B600AC6492 /* IobConsecutiveEventsTests.swift */; };
 		3BEDC9932EEB27B600AC6492 /* IobConsecutiveEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEDC9922EEB27B600AC6492 /* IobConsecutiveEventsTests.swift */; };
 		3BEF6AB12D9731660076089D /* MealHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEF6AB02D9731530076089D /* MealHistoryTests.swift */; };
 		3BEF6AB12D9731660076089D /* MealHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEF6AB02D9731530076089D /* MealHistoryTests.swift */; };
 		3BEF6AB32D97316F0076089D /* MealTotalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEF6AB22D97316A0076089D /* MealTotalTests.swift */; };
 		3BEF6AB32D97316F0076089D /* MealTotalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEF6AB22D97316A0076089D /* MealTotalTests.swift */; };
@@ -1270,7 +1268,6 @@
 		3B506FD82E635304000740B9 /* IOBService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBService.swift; sourceTree = "<group>"; };
 		3B506FD82E635304000740B9 /* IOBService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBService.swift; sourceTree = "<group>"; };
 		3B56079D2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeletedGlucoseStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		3B56079D2ECD62A800C723C1 /* DeletedGlucoseStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeletedGlucoseStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		3B56079F2ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeletedGlucoseStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		3B56079F2ECD62AC00C723C1 /* DeletedGlucoseStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeletedGlucoseStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
-		3B5CD1E92D4912A600CE213C /* OpenAPSSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAPSSwift.swift; sourceTree = "<group>"; };
 		3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONBridge.swift; sourceTree = "<group>"; };
 		3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONBridge.swift; sourceTree = "<group>"; };
 		3B5CD2912D4AEA3C00CE213C /* Basal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Basal.swift; sourceTree = "<group>"; };
 		3B5CD2912D4AEA3C00CE213C /* Basal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Basal.swift; sourceTree = "<group>"; };
 		3B5CD2922D4AEA3C00CE213C /* Carbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carbs.swift; sourceTree = "<group>"; };
 		3B5CD2922D4AEA3C00CE213C /* Carbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carbs.swift; sourceTree = "<group>"; };
@@ -1313,7 +1310,6 @@
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobTests.swift; sourceTree = "<group>"; };
 		3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobTests.swift; sourceTree = "<group>"; };
 		3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobBucketingTests.swift; sourceTree = "<group>"; };
 		3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobBucketingTests.swift; sourceTree = "<group>"; };
-		3BEA3ADE2D58F79700A67A1D /* OrefFunctionResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrefFunctionResult.swift; sourceTree = "<group>"; };
 		3BEDC9922EEB27B600AC6492 /* IobConsecutiveEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobConsecutiveEventsTests.swift; sourceTree = "<group>"; };
 		3BEDC9922EEB27B600AC6492 /* IobConsecutiveEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobConsecutiveEventsTests.swift; sourceTree = "<group>"; };
 		3BEF6AB02D9731530076089D /* MealHistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealHistoryTests.swift; sourceTree = "<group>"; };
 		3BEF6AB02D9731530076089D /* MealHistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealHistoryTests.swift; sourceTree = "<group>"; };
 		3BEF6AB22D97316A0076089D /* MealTotalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealTotalTests.swift; sourceTree = "<group>"; };
 		3BEF6AB22D97316A0076089D /* MealTotalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealTotalTests.swift; sourceTree = "<group>"; };
@@ -3079,8 +3075,6 @@
 				3B5CD2B22D4AEA6600CE213C /* Models */,
 				3B5CD2B22D4AEA6600CE213C /* Models */,
 				3B5CD2972D4AEA3C00CE213C /* Profile */,
 				3B5CD2972D4AEA3C00CE213C /* Profile */,
 				3B5CD2A02D4AEA5100CE213C /* Utils */,
 				3B5CD2A02D4AEA5100CE213C /* Utils */,
-				3B5CD1E92D4912A600CE213C /* OpenAPSSwift.swift */,
-				3BEA3ADE2D58F79700A67A1D /* OrefFunctionResult.swift */,
 				3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */,
 				3B5CD1EA2D4912A600CE213C /* JSONBridge.swift */,
 			);
 			);
 			path = OpenAPSSwift;
 			path = OpenAPSSwift;
@@ -5143,7 +5137,6 @@
 				582DF97B2C8CE209001F516D /* CarbView.swift in Sources */,
 				582DF97B2C8CE209001F516D /* CarbView.swift in Sources */,
 				DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */,
 				DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */,
 				3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */,
 				3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */,
-				3BEA3AE02D58F79700A67A1D /* OrefFunctionResult.swift in Sources */,
 				BD47FD1B2D88AB4F0043966B /* OnboardingStateModel.swift in Sources */,
 				BD47FD1B2D88AB4F0043966B /* OnboardingStateModel.swift in Sources */,
 				3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */,
 				3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */,
 				CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */,
 				CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */,
@@ -5434,7 +5427,6 @@
 				C29835B02E2AA3F30068C5BB /* NightscoutUploadStepView.swift in Sources */,
 				C29835B02E2AA3F30068C5BB /* NightscoutUploadStepView.swift in Sources */,
 				58D08B3A2C8DFECD00AA37D3 /* TempTargets.swift in Sources */,
 				58D08B3A2C8DFECD00AA37D3 /* TempTargets.swift in Sources */,
 				38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */,
 				38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */,
-				3B5CD1EC2D4912A600CE213C /* OpenAPSSwift.swift in Sources */,
 				3B5CD1ED2D4912A600CE213C /* JSONBridge.swift in Sources */,
 				3B5CD1ED2D4912A600CE213C /* JSONBridge.swift in Sources */,
 				CE7CA3542A064973004BE681 /* TempPresetsIntentRequest.swift in Sources */,
 				CE7CA3542A064973004BE681 /* TempPresetsIntentRequest.swift in Sources */,
 				58A3D5442C96DE11003F90FC /* TempTargetStored+Helper.swift in Sources */,
 				58A3D5442C96DE11003F90FC /* TempTargetStored+Helper.swift in Sources */,

+ 115 - 90
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -245,9 +245,6 @@ final class OpenAPS {
 
 
         let context = newContext("determineBasal")
         let context = newContext("determineBasal")
 
 
-        // temp_basal
-        let tempBasal = currentTemp.rawJSON
-
         // Perform asynchronous calls in parallel
         // Perform asynchronous calls in parallel
         async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
         async let pumpHistoryObjectIDs = fetchPumpHistoryObjectIDs(on: context) ?? []
         async let carbsFetch = carbsStorage.getCarbsForAlgorithm(
         async let carbsFetch = carbsStorage.getCarbsForAlgorithm(
@@ -274,11 +271,11 @@ final class OpenAPS {
             pumpHistory,
             pumpHistory,
             carbs,
             carbs,
             glucose,
             glucose,
-            trioCustomOrefVariables,
-            profile,
-            basalProfile,
-            autosens,
-            reservoir,
+            rawTrioCustomOrefVariables,
+            rawProfile,
+            rawBasalProfile,
+            rawAutosens,
+            rawReservoir,
             hasSufficientTdd
             hasSufficientTdd
         ) = await (
         ) = await (
             try parsePumpHistory(on: context, await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
             try parsePumpHistory(on: context, await pumpHistoryObjectIDs, simulatedBolusAmount: simulatedBolusAmount),
@@ -292,6 +289,16 @@ final class OpenAPS {
             try hasSufficientTddForDynamic
             try hasSufficientTddForDynamic
         )
         )
 
 
+        // Decode the JSON-at-rest inputs into native models at the call boundary.
+        // The bundled-defaults fallback still happens in loadFileFromStorageAsync
+        // above, so decoding here preserves the same behavior it previously had
+        // inside OpenAPSSwift.
+        let profile = try JSONBridge.profile(from: rawProfile)
+        let basalProfile = try JSONBridge.basalProfile(from: rawBasalProfile)
+        let autosens = try JSONBridge.autosens(from: rawAutosens.isEmpty ? .null : rawAutosens)
+        let reservoir = Decimal(string: rawReservoir) ?? 100
+        let trioCustomOrefVariables = try JSONBridge.trioCustomOrefVariables(from: rawTrioCustomOrefVariables)
+
         // Meal calculation
         // Meal calculation
         let meal = try self.meal(
         let meal = try self.meal(
             pumphistory: pumpHistory,
             pumphistory: pumpHistory,
@@ -307,7 +314,7 @@ final class OpenAPS {
             pumphistory: pumpHistory,
             pumphistory: pumpHistory,
             profile: profile,
             profile: profile,
             clock: clock,
             clock: clock,
-            autosens: autosens.isEmpty ? .null : autosens
+            autosens: autosens
         )
         )
 
 
         // TODO: refactor this to core data
         // TODO: refactor this to core data
@@ -324,21 +331,20 @@ final class OpenAPS {
         // Determine basal
         // Determine basal
         let orefDetermination = try determineBasal(
         let orefDetermination = try determineBasal(
             glucose: glucose,
             glucose: glucose,
-            currentTemp: tempBasal,
+            currentTemp: currentTemp,
             iob: iob,
             iob: iob,
             profile: profile,
             profile: profile,
-            autosens: autosens.isEmpty ? .null : autosens,
+            autosens: autosens,
             meal: meal,
             meal: meal,
             microBolusAllowed: true,
             microBolusAllowed: true,
             reservoir: reservoir,
             reservoir: reservoir,
             preferences: preferences,
             preferences: preferences,
-            basalProfile: basalProfile,
             trioCustomOrefVariables: trioCustomOrefVariables
             trioCustomOrefVariables: trioCustomOrefVariables
         )
         )
 
 
-        debug(.openAPS, "\(simulation ? "[SIMULATION]" : "") OREF DETERMINATION: \(orefDetermination)")
+        debug(.openAPS, "\(simulation ? "[SIMULATION]" : "") OREF DETERMINATION: \(String(describing: orefDetermination))")
 
 
-        if var determination = Determination(from: orefDetermination), let deliverAt = determination.deliverAt {
+        if var determination = orefDetermination, let deliverAt = determination.deliverAt {
             // set both timestamp and deliverAt to the SAME date; this will be updated for timestamp once it is enacted
             // set both timestamp and deliverAt to the SAME date; this will be updated for timestamp once it is enacted
             // AAPS does it the same way! we'll follow their example!
             // AAPS does it the same way! we'll follow their example!
             determination.timestamp = deliverAt
             determination.timestamp = deliverAt
@@ -352,7 +358,7 @@ final class OpenAPS {
         } else {
         } else {
             debug(
             debug(
                 .openAPS,
                 .openAPS,
-                "\(DebuggingIdentifiers.failed) No determination data. orefDetermination: \(orefDetermination), Determination(from: orefDetermination): \(String(describing: Determination(from: orefDetermination))), deliverAt: \(String(describing: Determination(from: orefDetermination)?.deliverAt))"
+                "\(DebuggingIdentifiers.failed) No determination data. determination: \(String(describing: orefDetermination)), deliverAt: \(String(describing: orefDetermination?.deliverAt))"
             )
             )
             throw APSError.apsError(message: "No determination data.")
             throw APSError.apsError(message: "No determination data.")
         }
         }
@@ -444,7 +450,7 @@ final class OpenAPS {
         async let getTempTargets = loadFileFromStorageAsync(name: Settings.tempTargets)
         async let getTempTargets = loadFileFromStorageAsync(name: Settings.tempTargets)
 
 
         // Await the results of asynchronous tasks
         // Await the results of asynchronous tasks
-        let (pumpHistory, carbs, glucose, profile, basalProfile, tempTargets) = await (
+        let (pumpHistory, carbs, glucose, rawProfile, rawBasalProfile, rawTempTargets) = await (
             try parsePumpHistory(on: context, await pumpHistoryObjectIDs),
             try parsePumpHistory(on: context, await pumpHistoryObjectIDs),
             try carbsFetch,
             try carbsFetch,
             try glucoseFetch,
             try glucoseFetch,
@@ -453,25 +459,27 @@ final class OpenAPS {
             getTempTargets
             getTempTargets
         )
         )
 
 
+        // Decode the JSON-at-rest inputs into native models at the call boundary.
+        let profile = try JSONBridge.profile(from: rawProfile)
+        let basalProfile = try JSONBridge.basalProfile(from: rawBasalProfile)
+        let tempTargets = try JSONBridge.tempTargets(from: rawTempTargets)
+
         // Autosense
         // Autosense
-        let autosenseResult = try autosense(
+        var autosens = try autosense(
             glucose: glucose,
             glucose: glucose,
             pumpHistory: pumpHistory,
             pumpHistory: pumpHistory,
-            basalprofile: basalProfile,
+            basalProfile: basalProfile,
             profile: profile,
             profile: profile,
             carbs: carbs,
             carbs: carbs,
-            temptargets: tempTargets
+            tempTargets: tempTargets,
+            clock: Date()
         )
         )
 
 
-        debug(.openAPS, "AUTOSENS: \(autosenseResult)")
-        if var autosens = Autosens(from: autosenseResult) {
-            autosens.timestamp = Date()
-            await storage.saveAsync(autosens, as: Settings.autosense)
+        debug(.openAPS, "AUTOSENS: \(autosens)")
+        autosens.timestamp = Date()
+        await storage.saveAsync(autosens, as: Settings.autosense)
 
 
-            return autosens
-        } else {
-            return nil
-        }
+        return autosens
     }
     }
 
 
     func createProfiles() async throws {
     func createProfiles() async throws {
@@ -550,24 +558,24 @@ final class OpenAPS {
             let carbRatios = try JSONBridge.carbRatios(from: carbRatios)
             let carbRatios = try JSONBridge.carbRatios(from: carbRatios)
             let tempTargets = try JSONBridge.tempTargets(from: tempTargets)
             let tempTargets = try JSONBridge.tempTargets(from: tempTargets)
 
 
-            let pumpProfile = try OpenAPSSwift.makeProfile(
-                preferences: adjustedPreferences,
+            let pumpProfile = try ProfileGenerator.generate(
                 pumpSettings: pumpSettings,
                 pumpSettings: pumpSettings,
                 bgTargets: bgTargets,
                 bgTargets: bgTargets,
                 basalProfile: basalProfile,
                 basalProfile: basalProfile,
-                insulinSensitivities: insulinSensitivities,
+                isf: insulinSensitivities,
+                preferences: adjustedPreferences,
                 carbRatios: carbRatios,
                 carbRatios: carbRatios,
                 tempTargets: tempTargets,
                 tempTargets: tempTargets,
                 model: model,
                 model: model,
                 clock: clock
                 clock: clock
             )
             )
 
 
-            let profile = try OpenAPSSwift.makeProfile(
-                preferences: adjustedPreferences,
+            let profile = try ProfileGenerator.generate(
                 pumpSettings: pumpSettings,
                 pumpSettings: pumpSettings,
                 bgTargets: bgTargets,
                 bgTargets: bgTargets,
                 basalProfile: basalProfile,
                 basalProfile: basalProfile,
-                insulinSensitivities: insulinSensitivities,
+                isf: insulinSensitivities,
+                preferences: adjustedPreferences,
                 carbRatios: carbRatios,
                 carbRatios: carbRatios,
                 tempTargets: tempTargets,
                 tempTargets: tempTargets,
                 model: model,
                 model: model,
@@ -588,88 +596,105 @@ final class OpenAPS {
 
 
     private func iob(
     private func iob(
         pumphistory: [PumpHistoryEvent],
         pumphistory: [PumpHistoryEvent],
-        profile: JSON,
-        clock: JSON,
-        autosens: JSON
-    ) throws -> RawJSON {
+        profile: Profile,
+        clock: Date,
+        autosens: Autosens?
+    ) throws -> [IobResult] {
         // FIXME: For now we'll just remove duplicate suspends here (ISSUE-399)
         // FIXME: For now we'll just remove duplicate suspends here (ISSUE-399)
         let pumphistory = pumphistory.removingDuplicateSuspendResumeEvents()
         let pumphistory = pumphistory.removingDuplicateSuspendResumeEvents()
 
 
-        let swiftResult = OpenAPSSwift
-            .iob(pumphistory: pumphistory, profile: profile, clock: clock, autosens: autosens)
-        return try swiftResult.returnOrThrow()
+        return try IobGenerator.generate(
+            history: pumphistory,
+            profile: profile,
+            clock: clock,
+            autosens: autosens
+        )
     }
     }
 
 
     private func meal(
     private func meal(
         pumphistory: [PumpHistoryEvent],
         pumphistory: [PumpHistoryEvent],
-        profile: JSON,
-        basalProfile: JSON,
-        clock: JSON,
+        profile: Profile,
+        basalProfile: [BasalProfileEntry],
+        clock: Date,
         carbs: [CarbsEntry],
         carbs: [CarbsEntry],
         glucose: [BloodGlucose]
         glucose: [BloodGlucose]
-    ) throws -> RawJSON {
-        let swiftResult = OpenAPSSwift
-            .meal(
-                pumphistory: pumphistory,
-                profile: profile,
-                basalProfile: basalProfile,
-                clock: clock,
-                carbs: carbs,
-                glucose: glucose
-            )
-        return try swiftResult.returnOrThrow()
+    ) throws -> ComputedCarbs? {
+        try MealGenerator.generate(
+            pumpHistory: pumphistory,
+            profile: profile,
+            basalProfile: basalProfile,
+            clock: clock,
+            carbHistory: carbs,
+            glucoseHistory: glucose
+        )
     }
     }
 
 
     private func autosense(
     private func autosense(
         glucose: [BloodGlucose],
         glucose: [BloodGlucose],
         pumpHistory: [PumpHistoryEvent],
         pumpHistory: [PumpHistoryEvent],
-        basalprofile: JSON,
-        profile: JSON,
+        basalProfile: [BasalProfileEntry],
+        profile: Profile,
         carbs: [CarbsEntry],
         carbs: [CarbsEntry],
-        temptargets: JSON
-    ) throws -> RawJSON {
-        let swiftResult = OpenAPSSwift
-            .autosense(
-                glucose: glucose,
-                pumpHistory: pumpHistory,
-                basalProfile: basalprofile,
-                profile: profile,
-                carbs: carbs,
-                tempTargets: temptargets,
-                clock: Date()
-            )
-        return try swiftResult.returnOrThrow()
+        tempTargets: [TempTarget],
+        clock: Date
+    ) throws -> Autosens {
+        // this logic is from prepare/autosens.js
+        let ratio8h = try AutosensGenerator.generate(
+            glucose: glucose,
+            pumpHistory: pumpHistory,
+            basalProfile: basalProfile,
+            profile: profile,
+            carbs: carbs,
+            tempTargets: tempTargets,
+            maxDeviations: 96,
+            clock: clock
+        )
+
+        let ratio24h = try AutosensGenerator.generate(
+            glucose: glucose,
+            pumpHistory: pumpHistory,
+            basalProfile: basalProfile,
+            profile: profile,
+            carbs: carbs,
+            tempTargets: tempTargets,
+            maxDeviations: 288,
+            clock: clock
+        )
+
+        return ratio8h.ratio < ratio24h.ratio ? ratio8h : ratio24h
     }
     }
 
 
     private func determineBasal(
     private func determineBasal(
         glucose: [BloodGlucose],
         glucose: [BloodGlucose],
-        currentTemp: JSON,
-        iob: JSON,
-        profile: JSON,
-        autosens: JSON,
-        meal: JSON,
+        currentTemp: TempBasal,
+        iob: [IobResult],
+        profile: Profile,
+        autosens: Autosens?,
+        meal: ComputedCarbs?,
         microBolusAllowed: Bool,
         microBolusAllowed: Bool,
-        reservoir: JSON,
-        preferences: JSON,
-        basalProfile: JSON,
-        trioCustomOrefVariables: JSON
-    ) throws -> RawJSON {
+        reservoir: Decimal,
+        preferences: Preferences,
+        trioCustomOrefVariables: TrioCustomOrefVariables
+    ) throws -> Determination? {
         let clock = Date()
         let clock = Date()
-        let swiftResult = OpenAPSSwift.determineBasal(
-            glucose: glucose,
-            currentTemp: currentTemp,
-            iob: iob,
+
+        guard let meal = meal, let autosens = autosens else {
+            throw DeterminationError.missingInputs
+        }
+
+        return try DeterminationGenerator.generate(
             profile: profile,
             profile: profile,
-            autosens: autosens,
-            meal: meal,
-            microBolusAllowed: microBolusAllowed,
-            reservoir: reservoir,
             preferences: preferences,
             preferences: preferences,
-            basalProfile: basalProfile,
+            currentTemp: currentTemp,
+            iobData: iob,
+            mealData: meal,
+            autosensData: autosens,
+            reservoirData: reservoir,
+            glucose: glucose,
+            microBolusAllowed: microBolusAllowed,
             trioCustomOrefVariables: trioCustomOrefVariables,
             trioCustomOrefVariables: trioCustomOrefVariables,
-            clock: clock
+            currentTime: clock
         )
         )
-        return try swiftResult.returnOrThrow()
     }
     }
 
 
     private func loadJSON(name: String) -> String {
     private func loadJSON(name: String) -> String {

+ 0 - 35
Trio/Sources/APS/OpenAPSSwift/JSONBridge.swift

@@ -8,10 +8,6 @@ enum JSONError: Error {
 }
 }
 
 
 enum JSONBridge {
 enum JSONBridge {
-    static func preferences(from: JSON) throws -> Preferences {
-        try JSONBridge.from(string: from.rawJSON)
-    }
-
     static func pumpSettings(from: JSON) throws -> PumpSettings {
     static func pumpSettings(from: JSON) throws -> PumpSettings {
         try JSONBridge.from(string: from.rawJSON)
         try JSONBridge.from(string: from.rawJSON)
     }
     }
@@ -40,49 +36,18 @@ enum JSONBridge {
         try JSONBridge.from(string: from.rawJSON)
         try JSONBridge.from(string: from.rawJSON)
     }
     }
 
 
-    static func currentTemp(from: JSON) throws -> TempBasal {
-        try JSONBridge.from(string: from.rawJSON)
-    }
-
-    static func iobResult(from: JSON) throws -> [IobResult] {
-        try JSONBridge.from(string: from.rawJSON)
-    }
-
     static func profile(from: JSON) throws -> Profile {
     static func profile(from: JSON) throws -> Profile {
         try JSONBridge.from(string: from.rawJSON)
         try JSONBridge.from(string: from.rawJSON)
     }
     }
 
 
-    static func computedCarbs(from: JSON) throws -> ComputedCarbs? {
-        try JSONBridge.from(string: from.rawJSON)
-    }
-
     static func autosens(from: JSON) throws -> Autosens? {
     static func autosens(from: JSON) throws -> Autosens? {
         try JSONBridge.from(string: from.rawJSON)
         try JSONBridge.from(string: from.rawJSON)
     }
     }
 
 
-    static func clock(from: JSON) throws -> Date {
-        let dateJson = from.rawJSON.replacingOccurrences(of: "\"", with: "").trimmingCharacters(in: .whitespacesAndNewlines)
-        if let date = Formatter.iso8601withFractionalSeconds.date(from: dateJson) ?? Formatter.iso8601
-            .date(from: dateJson)
-        {
-            return date
-        }
-
-        throw JSONError.invalidDate(from.rawJSON)
-    }
-
     static func from<T: Decodable>(string: String) throws -> T {
     static func from<T: Decodable>(string: String) throws -> T {
         guard let data = string.data(using: .utf8) else {
         guard let data = string.data(using: .utf8) else {
             throw JSONError.invalidString
             throw JSONError.invalidString
         }
         }
         return try JSONCoding.decoder.decode(T.self, from: data)
         return try JSONCoding.decoder.decode(T.self, from: data)
     }
     }
-
-    static func to<T: Encodable>(_ value: T) throws -> String {
-        let data = try JSONCoding.encoder.encode(value)
-        guard let string = String(data: data, encoding: .utf8) else {
-            throw JSONError.encodingFailed
-        }
-        return string
-    }
 }
 }

+ 1 - 1
Trio/Sources/APS/OpenAPSSwift/Models/IobResult.swift

@@ -1,6 +1,6 @@
 import Foundation
 import Foundation
 
 
-struct IobResult: Codable {
+struct IobResult: JSON {
     static func from(iob: IobTotal, iobWithZeroTemp: IobTotal) -> IobResult {
     static func from(iob: IobTotal, iobWithZeroTemp: IobTotal) -> IobResult {
         IobResult(
         IobResult(
             iob: iob.iob,
             iob: iob.iob,

+ 0 - 183
Trio/Sources/APS/OpenAPSSwift/OpenAPSSwift.swift

@@ -1,183 +0,0 @@
-import Foundation
-
-struct OpenAPSSwift {
-    static func makeProfile(
-        preferences: Preferences,
-        pumpSettings: PumpSettings,
-        bgTargets: BGTargets,
-        basalProfile: [BasalProfileEntry],
-        insulinSensitivities: InsulinSensitivities,
-        carbRatios: CarbRatios,
-        tempTargets: [TempTarget],
-        model: String,
-        clock: Date
-    ) throws -> Profile {
-        try ProfileGenerator.generate(
-            pumpSettings: pumpSettings,
-            bgTargets: bgTargets,
-            basalProfile: basalProfile,
-            isf: insulinSensitivities,
-            preferences: preferences,
-            carbRatios: carbRatios,
-            tempTargets: tempTargets,
-            model: model,
-            clock: clock
-        )
-    }
-
-    static func determineBasal(
-        glucose: [BloodGlucose],
-        currentTemp: JSON,
-        iob: JSON,
-        profile: JSON,
-        autosens: JSON,
-        meal: JSON,
-        microBolusAllowed: Bool,
-        reservoir: JSON,
-        preferences: JSON,
-        basalProfile: JSON,
-        trioCustomOrefVariables: JSON,
-        clock: Date
-    ) -> (OrefFunctionResult) {
-        do {
-            let currentTemp = try JSONBridge.currentTemp(from: currentTemp)
-            let iob = try JSONBridge.iobResult(from: iob)
-            let profile = try JSONBridge.profile(from: profile)
-            let autosens = try JSONBridge.autosens(from: autosens)
-            let meal = try JSONBridge.computedCarbs(from: meal)
-            let microBolusAllowed = microBolusAllowed
-            let reservoir = Decimal(string: reservoir.rawJSON)
-            let preferences = try JSONBridge.preferences(from: preferences)
-            let basalProfile = try JSONBridge.basalProfile(from: basalProfile)
-            let trioCustomOrefVariables = try JSONBridge.trioCustomOrefVariables(from: trioCustomOrefVariables)
-
-            guard let mealData = meal, let autosensData = autosens else {
-                return .failure(DeterminationError.missingInputs)
-            }
-
-            let rawDetermination = try DeterminationGenerator.generate(
-                profile: profile,
-                preferences: preferences,
-                currentTemp: currentTemp,
-                iobData: iob,
-                mealData: mealData,
-                autosensData: autosensData,
-                reservoirData: reservoir ?? 100,
-                glucose: glucose,
-                microBolusAllowed: microBolusAllowed,
-                trioCustomOrefVariables: trioCustomOrefVariables,
-                currentTime: clock
-            )
-
-            return try .success(JSONBridge.to(rawDetermination))
-
-        } catch let determinationError as DeterminationError {
-            // if we get a determination error we want to return it as a JSON
-            // object that is { "error": "some error" }
-            do {
-                let response = try JSONBridge.to(DeterminationErrorResponse(error: determinationError.localizedDescription))
-                return .success(response)
-            } catch {
-                return .failure(determinationError)
-            }
-        } catch {
-            return .failure(error)
-        }
-    }
-
-    static func meal(
-        pumphistory: [PumpHistoryEvent],
-        profile: JSON,
-        basalProfile: JSON,
-        clock: JSON,
-        carbs: [CarbsEntry],
-        glucose: [BloodGlucose]
-    ) -> (OrefFunctionResult) {
-        do {
-            let profile = try JSONBridge.profile(from: profile)
-            let basalProfile = try JSONBridge.basalProfile(from: basalProfile)
-            let clock = try JSONBridge.clock(from: clock)
-
-            let mealResult = try MealGenerator.generate(
-                pumpHistory: pumphistory,
-                profile: profile,
-                basalProfile: basalProfile,
-                clock: clock,
-                carbHistory: carbs,
-                glucoseHistory: glucose
-            )
-
-            return try .success(JSONBridge.to(mealResult))
-        } catch {
-            return .failure(error)
-        }
-    }
-
-    static func iob(pumphistory: [PumpHistoryEvent], profile: JSON, clock: JSON, autosens: JSON) -> (OrefFunctionResult) {
-        do {
-            let profile = try JSONBridge.profile(from: profile)
-            let clock = try JSONBridge.clock(from: clock)
-            let autosens = try JSONBridge.autosens(from: autosens)
-
-            let iobResult = try IobGenerator.generate(
-                history: pumphistory,
-                profile: profile,
-                clock: clock,
-                autosens: autosens
-            )
-
-            return try .success(JSONBridge.to(iobResult))
-        } catch {
-            return .failure(error)
-        }
-    }
-
-    static func autosense(
-        glucose: [BloodGlucose],
-        pumpHistory: [PumpHistoryEvent],
-        basalProfile: JSON,
-        profile: JSON,
-        carbs: [CarbsEntry],
-        tempTargets: JSON,
-        clock: JSON,
-        includeDeviationsForTesting: Bool = false
-    ) -> (OrefFunctionResult) {
-        do {
-            let basalProfile = try JSONBridge.basalProfile(from: basalProfile)
-            let profile = try JSONBridge.profile(from: profile)
-            let tempTargets = try JSONBridge.tempTargets(from: tempTargets)
-            let clock = try JSONBridge.clock(from: clock)
-
-            // this logic is from prepare/autosens.js
-            let ratio8h = try AutosensGenerator.generate(
-                glucose: glucose,
-                pumpHistory: pumpHistory,
-                basalProfile: basalProfile,
-                profile: profile,
-                carbs: carbs,
-                tempTargets: tempTargets,
-                maxDeviations: 96,
-                clock: clock,
-                includeDeviationsForTesting: includeDeviationsForTesting
-            )
-
-            let ratio24h = try AutosensGenerator.generate(
-                glucose: glucose,
-                pumpHistory: pumpHistory,
-                basalProfile: basalProfile,
-                profile: profile,
-                carbs: carbs,
-                tempTargets: tempTargets,
-                maxDeviations: 288,
-                clock: clock,
-                includeDeviationsForTesting: includeDeviationsForTesting
-            )
-
-            let lowestRatio = ratio8h.ratio < ratio24h.ratio ? ratio8h : ratio24h
-
-            return try .success(JSONBridge.to(lowestRatio))
-        } catch {
-            return .failure(error)
-        }
-    }
-}

+ 0 - 13
Trio/Sources/APS/OpenAPSSwift/OrefFunctionResult.swift

@@ -1,13 +0,0 @@
-import Foundation
-
-enum OrefFunctionResult {
-    case success(RawJSON)
-    case failure(Error)
-
-    func returnOrThrow() throws -> RawJSON {
-        switch self {
-        case let .success(json): return json
-        case let .failure(error): throw error
-        }
-    }
-}

+ 7 - 0
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -121601,6 +121601,9 @@
         }
         }
       }
       }
     },
     },
+    "End Snooze" : {
+
+    },
     "Endpoint" : {
     "Endpoint" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -260220,6 +260223,9 @@
         }
         }
       }
       }
     },
     },
+    "Swipe left to end snooze." : {
+
+    },
     "Swipe the chart to scroll through time." : {
     "Swipe the chart to scroll through time." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -315137,6 +315143,7 @@
       }
       }
     },
     },
     "You can disable this feature anytime." : {
     "You can disable this feature anytime." : {
+      "extractionState" : "stale",
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
           "stringUnit" : {
           "stringUnit" : {

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

@@ -1,9 +1,5 @@
 import Foundation
 import Foundation
 
 
-struct DeterminationErrorResponse: JSON, Equatable {
-    let error: String
-}
-
 struct Determination: JSON, Equatable {
 struct Determination: JSON, Equatable {
     let id: UUID?
     let id: UUID?
     var reason: String
     var reason: String