Skip to content

Commit 9e68991

Browse files
authored
Merge pull request #995 from LoopKit/merge-tidepool-dev
Merge tidepool dev
2 parents 8d4662e + e2c6bd5 commit 9e68991

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1781
-264
lines changed

Cartfile.resolved

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github "LoopKit/Amplitude-iOS" "2137d5fd44bf630ed33e1e72d7af6d8f8612f270"
2-
github "LoopKit/CGMBLEKit" "4194dbdabd4a2df390f41ada25bb99941fd165ca"
3-
github "LoopKit/G4ShareSpy" "4e4ea119d34d65cee35ccab9df0259e1dee52460"
4-
github "LoopKit/LoopKit" "346f5e85940fb56211035ae2e9f522512f17d0c0"
5-
github "LoopKit/dexcom-share-client-swift" "2179b253800dc527391ac582bdc9a0a7622e17c1"
2+
github "LoopKit/CGMBLEKit" "c4d73c4646591e43362f012b6a1b229a76d082ba"
3+
github "LoopKit/G4ShareSpy" "f6ae0cf1753131135f26046ddf07e096da884b84"
4+
github "LoopKit/LoopKit" "4eca69b9f2e3f1fc74e5b62484db00777c002cb7"
5+
github "LoopKit/dexcom-share-client-swift" "cdbb1cd19cf54b37add6d6c25300445a6abe24da"
66
github "i-schuetz/SwiftCharts" "0.6.5"
77
github "maxkonovalov/MKRingProgressView" "2.2.2"
88
github "ps2/rileylink_ios" "f616a671bac254b25c5e298f01824200944c2267"

Common/Extensions/GlucoseRangeSchedule.swift

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,8 @@ import HealthKit
1010

1111

1212
extension GlucoseRangeSchedule {
13-
func overrideEnabledForContext(_ context: Override.Context) -> Bool? {
14-
guard let override = override, override.context == context else {
15-
guard let value = overrideRanges[context], !value.isZero else {
16-
// Unavailable to set
17-
return nil
18-
}
19-
20-
return false
21-
}
22-
23-
return override.isActive()
24-
}
25-
26-
var activeOverride: GlucoseRangeSchedule.Override? {
27-
guard let override = override, override.isActive() else {
28-
return nil
29-
}
30-
31-
return override
32-
}
33-
34-
var activeOverrideContext: GlucoseRangeSchedule.Override.Context? {
35-
return activeOverride?.context
36-
}
37-
38-
var configuredOverrideContexts: [GlucoseRangeSchedule.Override.Context] {
39-
var contexts: [GlucoseRangeSchedule.Override.Context] = []
40-
for (context, range) in overrideRanges where !range.isZero {
41-
contexts.append(context)
42-
}
43-
44-
return contexts
13+
func minQuantity(at date: Date) -> HKQuantity {
14+
return HKQuantity(unit: unit, doubleValue: value(at: date).minValue)
4515
}
4616
}
4717

Common/FeatureFlags.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// FeatureFlags.swift
3+
// Loop
4+
//
5+
// Created by Michael Pangburn on 5/19/19.
6+
// Copyright © 2019 LoopKit Authors. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
12+
let FeatureFlags = FeatureFlagConfiguration()
13+
14+
struct FeatureFlagConfiguration: Decodable {
15+
let sensitivityOverridesEnabled: Bool
16+
17+
fileprivate init() {
18+
// Swift compiler config is inverse, since the default state is enabled.
19+
#if FEATURE_OVERRIDES_DISABLED
20+
self.sensitivityOverridesEnabled = false
21+
#else
22+
self.sensitivityOverridesEnabled = true
23+
#endif
24+
}
25+
}
70.3 KB
Loading
154 KB
Loading
149 KB
Loading
58.7 KB
Loading

Documentation/Testing/Scenarios.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Guide: Testing Scenarios
2+
3+
## Purpose
4+
5+
This document describes how to load data-based scenarios, including glucose values, dose history, and carb entries, into Loop on demand.
6+
7+
## File Format
8+
9+
A scenario consists of a single JSON file containing glucose, basal, bolus, and carb entry histories. Each history corresponds to a property of the scenario JSON object—a list of individual entries. Each entry has one or more properties describing its value (e.g. `unitsPerHourValue` and `duration`) and a _relative_ date offset, in seconds (e.g. 0 means 'right now' and -300 means '5 minutes ago').
10+
11+
For example, a carb entry history might look like this:
12+
13+
```json
14+
"carbEntries": [
15+
{
16+
"gramValue": 30,
17+
"dateOffset": -300,
18+
"absorptionTime": 10800
19+
},
20+
{
21+
"gramValue": 15,
22+
"dateOffset": 900,
23+
"absorptionTime": 7200,
24+
"enteredAtOffset": -900
25+
}
26+
]
27+
```
28+
29+
Carb entries have two date offsets: `dateOffset`, which describes the date at which carbs were consumed, and `enteredAtOffset`, which describes the date at which the carb entry was created. The second carb entry in the example above was entered 30 minutes early.
30+
31+
## Generating Scenarios
32+
33+
A Python script with classes corresponding to the entry types is available at `/Scripts/make_scenario.py`. Running it will generate a sample script, which will allow you to inspect the file format in more detail.
34+
35+
## Loading Scenarios
36+
37+
Launch Loop in the Xcode simulator.
38+
39+
Before loading scenarios, mock pump and CGM managers must be enabled in Loop. From the status screen, tap the settings icon in the bottom-right corner; then, tap on each of the pump and CGM rows and select the Simulator option from the presented action sheets:
40+
41+
![](Images/mock_managers.png)
42+
43+
Next, type 'scenario' in the search bar in the bottom-right corner of the Xcode console with the Loop app running:
44+
45+
![](Images/scenarios_url.png)
46+
47+
The first line will include `[TestingScenariosManager]` and a path to the simulator-specific directory in which to place scenario JSON files.
48+
49+
With one or more scenarios placed in the listed directory, the debug menu can be activated by "shaking" the iPhone: in the simulator, press ^⌘Z. The scenario selection screen will appear:
50+
51+
![](Images/scenarios_menu.png)
52+
53+
Tap on a scenario to select it, then press 'Load' in the top-right corner to load it into Loop.
54+
55+
With the app running, additional scenarios can be added to the scenarios directory; the changes will be detected, and the scenario list reloaded.
56+
57+
## Time Travel
58+
59+
Because all historic date offsets are relative, scenarios can be stepped through one or more loop iterations at a time, so long as the scenario contains sufficient past or future data.
60+
61+
Swiping right or left on a scenario cell reveals the 'rewind' or 'advance' button, respectively:
62+
63+
![](Images/rewind.png)
64+
65+
Tap on the button, and you will be prompted for a number of loop iterations to progress backward or forward in time. Note that advancing forward will run the full algorithm for each step and in turn apply the suggested basal at each decision point.
66+
67+
For convenience, an active scenario can be stepped through without leaving the status screen. Swipe right or left on the toolbar at the bottom of the screen to move one loop iteration into the past or future, respectively.

DoseMathTests/DoseMathTests.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class RecommendTempBasalTests: XCTestCase {
8484
}
8585

8686
var glucoseTargetRange: GlucoseRangeSchedule {
87-
return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])!
87+
return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))])!
8888
}
8989

9090
var insulinSensitivitySchedule: InsulinSensitivitySchedule {
@@ -120,6 +120,25 @@ class RecommendTempBasalTests: XCTestCase {
120120
XCTAssertNil(dose)
121121
}
122122

123+
func testNoChangeOverrideActive() {
124+
let glucose = loadGlucoseValueFixture("recommend_temp_basal_no_change_glucose")
125+
126+
let dose = glucose.recommendedTempBasal(
127+
to: glucoseTargetRange,
128+
at: glucose.first!.startDate,
129+
suspendThreshold: suspendThreshold.quantity,
130+
sensitivity: insulinSensitivitySchedule,
131+
model: insulinModel,
132+
basalRates: basalRateSchedule,
133+
maxBasalRate: maxBasalRate,
134+
lastTempBasal: nil,
135+
isBasalRateScheduleOverrideActive: true
136+
)
137+
138+
XCTAssertEqual(0.8, dose!.unitsPerHour, accuracy: 1.0 / 40.0)
139+
XCTAssertEqual(TimeInterval(minutes: 30), dose!.duration)
140+
}
141+
123142
func testStartHighEndInRange() {
124143
let glucose = loadGlucoseValueFixture("recommend_temp_basal_start_high_end_in_range")
125144

@@ -472,7 +491,7 @@ class RecommendBolusTests: XCTestCase {
472491
}
473492

474493
var glucoseTargetRange: GlucoseRangeSchedule {
475-
return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])!
494+
return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))])!
476495
}
477496

478497
var insulinSensitivitySchedule: InsulinSensitivitySchedule {

Loop.xcconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@
99
// This is automatically disambiguated by development team, but you may choose to change this to
1010
// support running multiple apps simultaneously.
1111
MAIN_APP_BUNDLE_IDENTIFIER = com.${DEVELOPMENT_TEAM}.loopkit
12+
MAIN_APP_DISPLAY_NAME = Loop
13+
14+
APPICON_NAME = AppIcon
15+
16+
// Exclude additional assets by default, and let other configurations that provide them add the file back in
17+
EXCLUDED_SOURCE_FILE_NAMES = AdditionalAssets.xcassets
18+
19+
// Optional workspace configuration overrides
20+
#include? "../LoopConfigOverride.xcconfig"
21+

0 commit comments

Comments
 (0)