Skip to content

Commit

Permalink
Override refactoring and additional functionnalities
Browse files Browse the repository at this point in the history
The PR includes a large refactoring of the swift part of override/profile functions :
- Override is stored in override core data, including history
- Override preset is stored in overridepreset core data
- Add the display of the override in main graph
- add the upload of override as a exercice in Nightscout - Fix nightscout#145
- improve the management of indefinate override / stop of indefinate override
- modify the code to respect the Ivan’s patterns of the app :
     - Use of swiftInject (dependency injection) with the use of protocol class in the code
     - Use of MVP principes, in particular not use of direct coredata in view class
     - Use of a proxy model class between coredata and the app to manage changes of core data
     - Use of the pattern of observe to refresh data/view/uploads

- add a core data unit tests allowing to add tests for coredata with a in-memory datastore for tests.
- test for overrideStorage available

This PR do NOT change the logic with oref and the interface of override informations in oref. This PR do NOT require a update of trio-oref code.

TODO : Changes the shortcuts after merging with PR nightscout#144  and add watch for overrides.
  • Loading branch information
avouspierre committed May 19, 2024
1 parent 5e51344 commit f1db386
Show file tree
Hide file tree
Showing 21 changed files with 1,138 additions and 335 deletions.
3 changes: 2 additions & 1 deletion Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23E224" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22222" systemVersion="23E224" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="BGaverages" representedClassName="BGaverages" syncable="YES" codeGenerationType="class">
<attribute name="average" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="average_1" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
Expand Down Expand Up @@ -65,6 +65,7 @@
<attribute name="isf" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="isfAndCr" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="isPreset" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="percentage" optional="YES" attributeType="Double" defaultValueString="100" usesScalarValueType="YES"/>
<attribute name="smbIsOff" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="smbIsScheduledOff" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
Expand Down
20 changes: 20 additions & 0 deletions FreeAPS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@
CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8BCB0C37DEB5EC377B9612 /* BasalProfileEditorRootView.swift */; };
CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */; };
CD78BB94E43B249D60CC1A1B /* NotificationsConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22963BD06A9C83959D4914E4 /* NotificationsConfigRootView.swift */; };
CE0295982BE65817003D5E97 /* OverrideStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0295972BE65817003D5E97 /* OverrideStorage.swift */; };
CE02959B2BE65A40003D5E97 /* OverrideProfil.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE02959A2BE65A40003D5E97 /* OverrideProfil.swift */; };
CE02959F2BE7A003003D5E97 /* TestCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE02959E2BE7A003003D5E97 /* TestCoreData.swift */; };
CE0295A12BE7A4F9003D5E97 /* OverrideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0295A02BE7A4F9003D5E97 /* OverrideTests.swift */; };
CE0BF4B52BEA6CAB004C00DD /* NightscoutExercice.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0BF4B42BEA6CAB004C00DD /* NightscoutExercice.swift */; };
CE1F6DD92BADF4620064EB8D /* PluginManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1F6DD82BADF4620064EB8D /* PluginManagerTests.swift */; };
CE1F6DDB2BAE08B60064EB8D /* TidepoolManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1F6DDA2BAE08B60064EB8D /* TidepoolManager.swift */; };
CE1F6DE72BAF1A180064EB8D /* BuildDetails.plist in Resources */ = {isa = PBXBuildFile; fileRef = CE1F6DE62BAF1A180064EB8D /* BuildDetails.plist */; };
Expand Down Expand Up @@ -812,6 +817,11 @@
C377490C77661D75E8C50649 /* ManualTempBasalRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalRootView.swift; sourceTree = "<group>"; };
C8D1A7CA8C10C4403D4BBFA7 /* BolusDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusDataFlow.swift; sourceTree = "<group>"; };
CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawFetchedProfile.swift; sourceTree = "<group>"; };
CE0295972BE65817003D5E97 /* OverrideStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStorage.swift; sourceTree = "<group>"; };
CE02959A2BE65A40003D5E97 /* OverrideProfil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProfil.swift; sourceTree = "<group>"; };
CE02959E2BE7A003003D5E97 /* TestCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestCoreData.swift; sourceTree = "<group>"; };
CE0295A02BE7A4F9003D5E97 /* OverrideTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideTests.swift; sourceTree = "<group>"; };
CE0BF4B42BEA6CAB004C00DD /* NightscoutExercice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutExercice.swift; sourceTree = "<group>"; };
CE1F6DD82BADF4620064EB8D /* PluginManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginManagerTests.swift; sourceTree = "<group>"; };
CE1F6DDA2BAE08B60064EB8D /* TidepoolManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TidepoolManager.swift; sourceTree = "<group>"; };
CE1F6DE62BAF1A180064EB8D /* BuildDetails.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = BuildDetails.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1602,13 +1612,15 @@
19012CDB291D2CB900FB8210 /* LoopStats.swift */,
FE41E4D329463C660047FD55 /* NightscoutStatistics.swift */,
FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
CE0BF4B42BEA6CAB004C00DD /* NightscoutExercice.swift */,
191F62672AD6B05A004D7911 /* NightscoutSettings.swift */,
1967DFBD29D052C200759F30 /* Icons.swift */,
19D4E4EA29FC6A9F00351451 /* TIRforChart.swift */,
19A910352A24D6D700C8951B /* DateFilter.swift */,
193F6CDC2A512C8F001240FD /* Loops.swift */,
CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */,
BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
CE02959A2BE65A40003D5E97 /* OverrideProfil.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -1656,6 +1668,7 @@
38F3B2EE25ED8E2A005C48AA /* TempTargetsStorage.swift */,
CE82E02428E867BA00473A9C /* AlertStorage.swift */,
1956FB202AFF79E200C7B4FF /* CoreDataStorage.swift */,
CE0295972BE65817003D5E97 /* OverrideStorage.swift */,
);
path = Storage;
sourceTree = "<group>";
Expand Down Expand Up @@ -1830,6 +1843,8 @@
38FCF3F825E902C20078B0D1 /* FileStorageTests.swift */,
CE1F6DD82BADF4620064EB8D /* PluginManagerTests.swift */,
CEE9A65D2BBC9F6500EB5194 /* CalibrationsTests.swift */,
CE02959E2BE7A003003D5E97 /* TestCoreData.swift */,
CE0295A02BE7A4F9003D5E97 /* OverrideTests.swift */,
);
path = FreeAPSTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -2708,6 +2723,7 @@
3883581C25EE79BB00E024B2 /* DecimalTextField.swift in Sources */,
6B1A8D2E2B156EEF00E76752 /* LiveActivityBridge.swift in Sources */,
38DAB28A260D349500F74C1A /* FetchGlucoseManager.swift in Sources */,
CE02959B2BE65A40003D5E97 /* OverrideProfil.swift in Sources */,
38F37828261260DC009DB701 /* Color+Extensions.swift in Sources */,
3811DE3F25C9D4A100A708ED /* SettingsStateModel.swift in Sources */,
CE7CA3582A064E2F004BE681 /* ListStateView.swift in Sources */,
Expand Down Expand Up @@ -2747,6 +2763,7 @@
E974172296125A5AE99E634C /* PumpConfigRootView.swift in Sources */,
CE7CA3522A064973004BE681 /* ListTempPresetsIntent.swift in Sources */,
448B6FCB252BD4796E2960C0 /* PumpSettingsEditorDataFlow.swift in Sources */,
CE0BF4B52BEA6CAB004C00DD /* NightscoutExercice.swift in Sources */,
38E44536274E411700EC9A94 /* Disk.swift in Sources */,
2BE9A6FA20875F6F4F9CD461 /* PumpSettingsEditorProvider.swift in Sources */,
6B9625766B697D1C98E455A2 /* PumpSettingsEditorStateModel.swift in Sources */,
Expand All @@ -2767,6 +2784,7 @@
FA630397F76B582C8D8681A7 /* BasalProfileEditorProvider.swift in Sources */,
63E890B4D951EAA91C071D5C /* BasalProfileEditorStateModel.swift in Sources */,
38FEF3FA2737E42000574A46 /* BaseStateModel.swift in Sources */,
CE0295982BE65817003D5E97 /* OverrideStorage.swift in Sources */,
CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */,
385CEA8225F23DFD002D6D5B /* NightscoutStatus.swift in Sources */,
F90692AA274B7AAE0037068D /* HealthKitManager.swift in Sources */,
Expand Down Expand Up @@ -2900,7 +2918,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CE02959F2BE7A003003D5E97 /* TestCoreData.swift in Sources */,
CEE9A65E2BBC9F6500EB5194 /* CalibrationsTests.swift in Sources */,
CE0295A12BE7A4F9003D5E97 /* OverrideTests.swift in Sources */,
CE1F6DD92BADF4620064EB8D /* PluginManagerTests.swift in Sources */,
38FCF3F925E902C20078B0D1 /* FileStorageTests.swift in Sources */,
);
Expand Down
5 changes: 4 additions & 1 deletion FreeAPS/Sources/APS/APSManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ final class BaseAPSManager: APSManager, Injectable {
@Injected() private var settingsManager: SettingsManager!
@Injected() private var broadcaster: Broadcaster!
@Injected() private var healthKitManager: HealthKitManager!
@Injected() private var overrideStorage: OverrideStorage!
@Persisted(key: "lastAutotuneDate") private var lastAutotuneDate = Date()
@Persisted(key: "lastStartLoopDate") private var lastStartLoopDate: Date = .distantPast
@Persisted(key: "lastLoopDate") var lastLoopDate: Date = .distantPast {
Expand Down Expand Up @@ -359,10 +360,12 @@ final class BaseAPSManager: APSManager, Injectable {
let now = Date()
let temp = currentTemp(date: now)

let eventuelOverride: OverrideProfil? = overrideStorage.current()

let mainPublisher = makeProfiles()
.flatMap { _ in self.autosens() }
.flatMap { _ in self.dailyAutotune() }
.flatMap { _ in self.openAPS.determineBasal(currentTemp: temp, clock: now) }
.flatMap { _ in self.openAPS.determineBasal(currentTemp: temp, clock: now, override: eventuelOverride) }
.map { suggestion -> Bool in
if let suggestion = suggestion {
DispatchQueue.main.async {
Expand Down
100 changes: 40 additions & 60 deletions FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ final class OpenAPS {
self.storage = storage
}

func determineBasal(currentTemp: TempBasal, clock: Date = Date()) -> Future<Suggestion?, Never> {
func determineBasal(
currentTemp: TempBasal,
clock: Date = Date(),
override: OverrideProfil? = nil
) -> Future<Suggestion?, Never> {
Future { promise in
self.processQueue.async {
debug(.openAPS, "Start determineBasal")
Expand Down Expand Up @@ -61,7 +65,7 @@ final class OpenAPS {
let preferences = self.loadFileFromStorage(name: Settings.preferences)

// oref2
let oref2_variables = self.oref2()
let oref2_variables = self.oref2(override)

let suggested = self.determineBasal(
glucose: glucose,
Expand Down Expand Up @@ -118,13 +122,13 @@ final class OpenAPS {
}
}

func oref2() -> RawJSON {
func oref2(_ override: OverrideProfil? = nil) -> RawJSON {
coredataContext.performAndWait {
let preferences = storage.retrieve(OpenAPS.Settings.preferences, as: Preferences.self)
var hbt_ = preferences?.halfBasalExerciseTarget ?? 160
let wp = preferences?.weightPercentage ?? 1
let smbMinutes = (preferences?.maxSMBBasalMinutes ?? 30) as NSDecimalNumber
let uamMinutes = (preferences?.maxUAMSMBBasalMinutes ?? 30) as NSDecimalNumber
let smbMinutes = preferences?.maxSMBBasalMinutes ?? 30
let uamMinutes = preferences?.maxUAMSMBBasalMinutes ?? 30

let tenDaysAgo = Date().addingTimeInterval(-10.days.timeInterval)
let twoHoursAgo = Date().addingTimeInterval(-2.hours.timeInterval)
Expand All @@ -143,13 +147,6 @@ final class OpenAPS {
// requestIsEnbled.fetchLimit = 1
try? sliderArray = coredataContext.fetch(requestIsEnbled)

var overrideArray = [Override]()
let requestOverrides = Override.fetchRequest() as NSFetchRequest<Override>
let sortOverride = NSSortDescriptor(key: "date", ascending: false)
requestOverrides.sortDescriptors = [sortOverride]
// requestOverrides.fetchLimit = 1
try? overrideArray = coredataContext.fetch(requestOverrides)

var tempTargetsArray = [TempTargets]()
let requestTempTargets = TempTargets.fetchRequest() as NSFetchRequest<TempTargets>
let sortTT = NSSortDescriptor(key: "date", ascending: false)
Expand All @@ -167,11 +164,8 @@ final class OpenAPS {
var temptargetActive = tempTargetsArray.first?.active ?? false
let isPercentageEnabled = sliderArray.first?.enabled ?? false

var useOverride = overrideArray.first?.enabled ?? false
var overridePercentage = Decimal(overrideArray.first?.percentage ?? 100)
var unlimited = overrideArray.first?.indefinite ?? true
var disableSMBs = overrideArray.first?.smbIsOff ?? false

let unlimited = override?.indefinite ?? true
let disableSMBs = override?.smbIsOff ?? false
let currentTDD = (uniqueEvents.last?.tdd ?? 0) as Decimal

if indeces == 0 {
Expand All @@ -187,36 +181,22 @@ final class OpenAPS {
let weight = wp
let weighted_average = weight * average2hours + (1 - weight) * average14

let useOverride = (override != nil)
var overridePercentage = Decimal(override?.percentage ?? 100)
var duration: Decimal = 0
var newDuration: Decimal = 0
var overrideTarget: Decimal = 0
var smbMin: Decimal = smbMinutes
var uamMin: Decimal = uamMinutes

if useOverride {
duration = (overrideArray.first?.duration ?? 0) as Decimal
overrideTarget = (overrideArray.first?.target ?? 0) as Decimal
let advancedSettings = overrideArray.first?.advancedSettings ?? false
let addedMinutes = Int(duration)
let date = overrideArray.first?.date ?? Date()
if date.addingTimeInterval(addedMinutes.minutes.timeInterval) < Date(),
!unlimited
{
useOverride = false
let saveToCoreData = Override(context: self.coredataContext)
saveToCoreData.enabled = false
saveToCoreData.date = Date()
saveToCoreData.duration = 0
saveToCoreData.indefinite = false
saveToCoreData.percentage = 100
try? self.coredataContext.save()
duration = override?.duration ?? 0
overrideTarget = override?.target ?? 0
if let sm = override?.smbMinutes {
smbMin = sm > 0 ? sm : smbMinutes
}
if let um = override?.uamMinutes {
uamMin = um > 0 ? um : uamMinutes
}
}

if !useOverride {
unlimited = true
overridePercentage = 100
duration = 0
overrideTarget = 0
disableSMBs = false
}

if temptargetActive {
Expand Down Expand Up @@ -255,15 +235,15 @@ final class OpenAPS {
hbt: hbt_,
overrideTarget: overrideTarget,
smbIsOff: disableSMBs,
advancedSettings: overrideArray.first?.advancedSettings ?? false,
isfAndCr: overrideArray.first?.isfAndCr ?? false,
isf: overrideArray.first?.isf ?? false,
cr: overrideArray.first?.cr ?? false,
smbIsScheduledOff: overrideArray.first?.smbIsScheduledOff ?? false,
start: (overrideArray.first?.start ?? 0) as Decimal,
end: (overrideArray.first?.end ?? 0) as Decimal,
smbMinutes: (overrideArray.first?.smbMinutes ?? smbMinutes) as Decimal,
uamMinutes: (overrideArray.first?.uamMinutes ?? uamMinutes) as Decimal
advancedSettings: override?.advancedSettings ?? false,
isfAndCr: override?.isfAndCr ?? false,
isf: override?.isf ?? false,
cr: override?.cr ?? false,
smbIsScheduledOff: override?.smbIsScheduledOff ?? false,
start: override?.start ?? 0,
end: override?.end ?? 0,
smbMinutes: smbMin,
uamMinutes: uamMin
)
storage.save(averages, as: OpenAPS.Monitor.oref2_variables)
return self.loadFileFromStorage(name: Monitor.oref2_variables)
Expand All @@ -283,15 +263,15 @@ final class OpenAPS {
hbt: hbt_,
overrideTarget: overrideTarget,
smbIsOff: disableSMBs,
advancedSettings: overrideArray.first?.advancedSettings ?? false,
isfAndCr: overrideArray.first?.isfAndCr ?? false,
isf: overrideArray.first?.isf ?? false,
cr: overrideArray.first?.cr ?? false,
smbIsScheduledOff: overrideArray.first?.smbIsScheduledOff ?? false,
start: (overrideArray.first?.start ?? 0) as Decimal,
end: (overrideArray.first?.end ?? 0) as Decimal,
smbMinutes: (overrideArray.first?.smbMinutes ?? smbMinutes) as Decimal,
uamMinutes: (overrideArray.first?.uamMinutes ?? uamMinutes) as Decimal
advancedSettings: override?.advancedSettings ?? false,
isfAndCr: override?.isfAndCr ?? false,
isf: override?.isf ?? false,
cr: override?.cr ?? false,
smbIsScheduledOff: override?.smbIsScheduledOff ?? false,
start: override?.start ?? 0,
end: override?.end ?? 0,
smbMinutes: smbMin,
uamMinutes: uamMin
)
storage.save(averages, as: OpenAPS.Monitor.oref2_variables)
return self.loadFileFromStorage(name: Monitor.oref2_variables)
Expand Down
Loading

0 comments on commit f1db386

Please sign in to comment.