Customize Your Loop
Build then Customize¶
For new Loopers, please build the code before you make any changes. Start with Open Loop and familiarize yourself with the interface. Later, you can make the customization(s) you desire and build again. The second build will be much easier than your first build.
These customizations require you to build the Loop app onto your iPhone, they cannot be done from within the app itself.
Customization Options¶
Read about the customizations on this page before applying them.
You take responsibility
You are responsible when you decide to use customizations.
Be sure to report what changes you made if you need to ask for assistance with your app.
Some customizations are the same for everyone and have been prepared for easy use.
- Mac-Xcode builders can use the Loop and Learn: Loop Customizations script
- This script automatically finds the most recent download and when you are done selecting customizations, opens Xcode to that download
- Even if you don't want to apply customizations, you can use this script as a easy way to find and open your download
- GitHub builders can use Loop and Learn: Customization: Single Customization List
Other customizations require that you create your own personalized version.
- Mac-Xcode builders: all the information required is on this page
- GitHub builders: read this page and use LoopDocs: GitHub Customization
For GitHub Browser Build, you can skip over the Mac-Xcode specific section and skip ahead to Build-Time Features.
When applying a customization using Mac-Xcode, the downloaded code should be fairly recent. If you are not sure, get a fresh download. If you know your downloaded code is the Current Release, you can skip the download and use the same folder as last time.
Find My Downloaded Loop Code¶
Refer to the graphic below. The Downloads folder in Finder is highlighted on the upper left. The full path to Loop.xcworkspace is highlighted along the bottom.
Loop to LoopWorkspace
Note that the directory Loop.xcworkspace
has been renamed to LoopWorkspace.xcworkspace
in the released code. For experienced builders - you realize this is good because the build process is easier.
The words were updated, but it will take time for the graphics to be updated.
- Open Finder
- Navigate to Downloads/BuildLoop and look for your download by name and date
- Open that folder, for example, Downloads/BuildLoop/Loop-220803-1145, and inside that folder open the LoopWorkspace folder
- Inside the Downloads/BuildLoop/Loop-220803-1145/LoopWorkspace folder, double-click on LoopWorkspace.xcworkspace (graphic not updated yet)
- Xcode automatically opens to that particular download
- You can then make the customizations and build to your phone
Experienced Builders
Experienced builders will often build a fresh download to a simulator for their phone iOS (not their phone) to ensure download is good and is compatible with macOS, Xcode and phone iOS. Once the build is successful, they apply their customizations and build again to the simulator. Last step is to build the customized version to their real phone.
Be sure to read the Instructions for Finding the Lines.
Line numbers may change
Every effort will be made to update the line numbers as the code is updated, but there may be times where the screenshots and line numbers differ from the current version of Loop code.
-
You may notice some customizations list line numbers for different branches
-
If you cannot identify a line that looks exactly like the example - do not guess - go to your favorite social media group and ask for help
Loop 2.2.x vs Loop 3
- Loop 3 has been released but there are some people using older code.
- The labels below indicate Loop 2.2.x or Loop 3, if they are different
- Users of Loop 2.2.9 (or earlier) or FreeAPS should refer to the Loop 2.2.x examples.
- Some 2.2.x customizations will be removed as time goes on
- Users of Loop 3 should refer to the Loop 3 examples.
- Note that some changes are in a different file for Loop 3 (part of the architecture upgrade for the app).
Build-Time Features¶
Build-time features are not available with Loop 2.2.x.
With Loop 3, some features are enabled or disabled by default but can be modified by adding a "flag" to a particular line in the LoopConfigOverride.xcconfig file.
If you use the GitHub Build Method, these build-time features can be added to your copy of the LoopConfigOverride.xcconfig file. Use the pencil icon in that file on GitHub and then commit the change to your fork.
If you use the Mac-Xcode Build Method, this is the same file used to automatically sign all your targets. You can edit the version in your LoopWorkspace folder (it shows up as the top item in the Xcode folder view) - or - if you use the build script, you can edit the copy found in ~/Downloads/BuildLoop after the first time you use the script. For that second case, the "flags" you add in ~/Downloads/BuildLoop/LoopConfigOverride.xcconfig are applied to all downloads created with the script.
These flags are always upper case with underscore separating words for clarity. They are inserted anywhere after the word $(inherited)
and before the //
. The //
indicates the flags to the right are not included. In the line shown below, simulators are enabled but debug features are turned off. Each flag is separated by a space. Do not enter a return between selections - Xcode will word-wrap the line for clarity, but all values need to be on a single line.
Code Before Modification
// Features
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) SIMULATORS_ENABLED //DEBUG_FEATURES_ENABLED
The example below is for someone who is using a Free Developer ID - which does not support Siri.
Code After Modification
// Features
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) SIRI_DISABLED SIMULATORS_ENABLED //DEBUG_FEATURES_ENABLED
List of some flags and what they do:
FLAG | PURPOSE |
---|---|
SIRI_DISABLED | Required to build Loop from Xcode with a free developer account |
ADULT_CHILD_INSULIN_MODEL_SELECTION_ENABLED | The choice for Child Model is enabled in Therapy Settings. Please read Enable Child Model. |
REMOTE_OVERRIDES_DISABLED | Remote commands: override, carbs or boluses will not be accepted even if all the Remote Command requirements are configured |
OBSERVE_HEALTH_KIT_CARB_SAMPLES_FROM_OTHER_APPS_ENABLED | Turns on ability for Loop to read third party carb entries. You must also make sure Health permissions allow Loop to read carbs from Health. Be vigilant if you select this; added carbs lead to added insulin dosing when closed loop is enabled |
SHOW_EVENTUAL_BLOOD_GLUCOSE_ON_WATCH_DISABLED | The Apple Watch screens show current glucose, trend arrow and eventual glucose by default. This flag disables the display of eventual glucose on the watch if you find the display distracting. |
Instructions for Finding the Lines¶
The instructions on this page were originally prepared for the Mac-Xcode method.
The GitHub Browser Build method instructions are similar, but each one is used to edit your fork of the particular Module in your GitHub account as instructed on the Customize with GitHub page.
For each customization, you will be given landmarks to find the correct location in the code. You can choose to search using the Key_Phrase
or navigate to the file in the folder structure and look for ( Cmd+L # ) the line number.
Some customizations are the same for all users, and do not require personalization. See Loop and Learn: Customization: Single Customization List.
For Mac-Xcode builders:
- Either Key_Phrase or Module, Folder, File can be used to find the lines
- Be sure to save the file when you make a change - otherwise the modification does not get built into your app
- Some folder icons show different names in Xcode, see Folders and Icons
For GitHub Browser builders;
- Some customizations can be copied from the Loop and Learn: Customization: Single Customization List
- Otherwise, create your own customization for the Module identified under Module, Folder, File as instructed on the Customize with GitHub page
Key_Phrase¶
use the copy button at right, paste into search
The copy button for this exampe is just for practice
Do not paste the result anywhere
To search using the Key_Phrase
(see graphic below for clarification):
- A copy button is available when you hover your mouse in the right-hand side of the block below the title
Key_Phrase
; click on it to copy the phrase - In Xcode, tap the Find menu item and select
Find in Workspace
- Paste the text into the Find search-box that opens on upper left of Xcode screen and hit enter
- If you don't see the phrase in the box, hit backspace - your system copied an extra return
- You should see a message
1 result in 1 file
(for most cases)- Some customizations will show more than one result, but that will be explained in the directions for that customization
- The file in which the line is located is reported showing the line in that file containing the
Key_Phrase
- Click on the one you think is correct and it will display in the main middle window of Xcode with the Keyword highlighted on the line you selected
- The
Key_Phrase
was selected to limit the search to just the relevant line (if possible) - In some cases, the
Key_Phrase
gets you close but not exactly on the line where you need to make the modifications - please read carefully
- The
Module, Folder, File¶
Each customization will also show Module, Folder and File bullet below the key phrase.
- Module: Loop
- Folder: Loop/subfolder1/subfolder2/etc.
- File: filename.swift, line number(s)
Customizations:¶
The customizations below show the original line of code that you will be changing.
There may be a figure illustrating the change.
Below the figure, the original, and in some cases, the modified code will be displayed as text.
- Sometimes that line is long and you may need to use the scroll bar to see the entire line in LoopDocs
- In most cases, an example customization is shown to assist you in deciding how to edit the line to meet your needs
Disable Authentication for Bolusing¶
Depending on your iPhone preferences and model, you may have Face ID or Touch ID enabled. Those security features will also be used to authenticate bolus delivery in Loop. You can choose to disable authentication (i.e., not require Face ID, Touch ID, or passcode for bolusing) through the following code customization.
Safety Measure
If you disable this, you are removing an important safety feature.
In addition to authenticating every manual bolus, this helps to protect against sleep bolusing and pocket bolusing.
For Loop 3, this controls the authorization requirement to modify Therapy Settings as well as to confirm bolus delivery.
canEvaluatePolicy(.deviceOwnerAuthentication
- Module: LoopKit
- Loop 3
- Folder: LoopKit/LoopKitUI/Extensions/
- File: Environment+Authenticate.swift, Line 20
Loop 3¶
Code Before Modification
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
Code After Modification
if false && context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
Loop 2.2.x¶
- Loop 2.2.x
- Folder: Loop/View Controllers
- File: BolusViewController.swift, Line 529
The screenshot below was taken with Loop v2.0 when the line number was 201; with Loop 2.2.x versions, that same code is found at line 529. Add the false &&
as shown in the screenshot below:
Code Before Modification
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) {
Code After Modification
if false && context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) {
Default Carb Absorption Times¶
Loop’s default carb absorption times are based on the high, medium, and low glycemic index absorption curves presented in Think Like A Pancreas by Gary Scheiner. With Loop 2.2.x, the lollipop (fast) icon is set for 2 hours, taco (medium) icon for 3 hours, and pizza (slow) icon for 4 hours. This is modified for Loop 3 to 30 minutes, 3 hours and 5 hours respectively.
defaultCarbAbsorptionTimes: CarbStore.DefaultAbsorptionTimes
- Module: Loop
-
Loop 3
- Folder: Loop/LoopCore
- File: LoopCoreConstants.swift
- Line: 16
-
Loop 2.2.x
- Folder: Loop/LoopCore
- File: LoopSettings.swift
- Line: 16 (2.2.4 master), 41 (2.2.4 AB), 50 (2.2.5 and later)
For example, if you wanted to modify Loop 2.2.9 so that lollipop represents a 30 minute absorption and pizza a 5 hour absorption, the edit would be as follows:
Code Before Modification for Loop 2.2.x
public static let defaultCarbAbsorptionTimes: CarbStore.DefaultAbsorptionTimes = (fast: .hours(2), medium: .hours(3), slow: .hours(4))
Code After Modification or default for Loop 3
public static let defaultCarbAbsorptionTimes: CarbStore.DefaultAbsorptionTimes = (fast: .minutes(30), medium: .hours(3), slow: .hours(5))
Note that if you change from 2 hours to 30 minutes, you must also change the indication before the parentheses.
Adjust Percent Bolus for Automatic Bolus¶
If you are mostly happy with the Dosing Strategy of Automatic Bolus but wish it delivered more or less insulin during every Loop interval, then this customization is for you.
This customization changes the percent of the recommended bolus used for automatic delivery. The method for calculating that recommendation is not changed by this modification. The default value is 40% (0.4). It is recommended you take small changes of 0.1 at a time. Once you modify it once and try it out for a while, it’s easy to go back and change it again.
Change just the number and double check that the value is less than 1.
let bolusPartialApplicationFactor
- Module: Loop
- Loop 3
- Folder: Loop/Loop/Models
- File: LoopConstants.swift
- Line: 53
Code Before Modification
static let bolusPartialApplicationFactor = 0.4
Code After Modification to 50% of recommended insulin
static let bolusPartialApplicationFactor = 0.5
Do not exceed 1.0
This number should never be bigger than 1 (you’d be getting more than Loop recommends). If you think you need more than 1, consider your settings and meal entries.
Modify Override Insulin Needs Picker¶
Some people want finer settings on the override insulin needs picker (5% instead of 10%) and may want to limit the overall range for overrides – especially for children.
1% Settings Available without Customization
With the advent of Loop 3, the Override Insulin Needs values are not limited by the default picker values of 10%.
- Not available in Loop 2.2.x
- Not available in FreeAPS (based off Loop 2.2.x)
- Select 1% Insulin Needs
Any override more than a factor of 2 from 100% can cause Loop predictions to be wrong – especially if a carb count is entered. (An override is NOT the same as a manual temp basal - it changes insulin sensitivity factor and carb ratio in addition to the basal rate needed for zero change in IOB for the duration of the override.)
A Sensitivity of 0% is NOT Valid
Do not set the lower level of the sensitivity range to be 0%.
If you configure to allow that and someone chooses it, they will be telling Loop to divide by zero in some of the calculations. They will see NaN (not a number) in Loop predictions until that override is removed and will continue to see that for the full duration of insulin action (6 hours).
This example customization changes the lower bound for sensitivity to 50% (factor of 2 smaller than 100%) and provides 5% steps.
let allScaleFactorPercentages
- Module: LoopKit
- Folder: LoopKit/LoopKitUI/Views
- File: InsulinSensitivityScalingTableViewCell.swift, Line 19
Code Before Modification
private let allScaleFactorPercentages = Array(stride(from: 10, through: 200, by: 10))
Code After Modification to 50% to 200% by steps of 5%
private let allScaleFactorPercentages = Array(stride(from: 50, through: 200, by: 5))
Modify Maximum and Warning Carb Entry¶
Loop 3 Carb Entry Variables¶
Loop 3 has both a maxCarbEntryQuantity and a warningCarbEntryQuantity, found adjacent to each other in the code. The warning value is the level at which you are asked if you really meant to enter that amount:
let maxCarbEntryQuantity =
- Module: Loop
- Folder: Loop/Loop/Models
- File: LoopConstants.swift, line 18
Code Before Modification
static let maxCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 250) // cannot exceed this value
static let warningCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 99) // user is warned above this value
This first example might be used by a parent for a child with very small carb entries.
Code After Modification to enable the warning at lower levels and limit maximum
static let maxCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 99) // cannot exceed this value
static let warningCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 49) // user is warned above this value
This second example might be used by a person who routinely enters large meals and does not want to be warned with every meal.
Code After Modification to warn if entry is between 201 and 300g
static let maxCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 300) // cannot exceed this value
static let warningCarbEntryQuantity = HKQuantity(unit: .gram(), doubleValue: 200) // user is warned above this value
Loop 2.2.x Max Carb Entry¶
Users of Loop 2.2.9 and earlier or FreeAPS must use the following method for modifying maximum carb entry:
Some people want to limit the maximum number of carbs that can be entered in one entry – especially for children or folks who eat lower carb. This helps prevent accidental typos, e.g., entry of 115 g instead of 15 g for a meal.
maxQuantity =
As shown in the graphic below, this phrase shows up in 2 places, only the first one should be modified.
- Loop 2.2.x
- Folder: Loop/Loop/View Controllers
- File: CarbEntryViewController.swift, Line 33 (Loop 2.2.x)
Code Before Modification
var maxQuantity = HKQuantity(unit: .gram(), doubleValue: 250)
Code After Modification to limit carb entry to 99 g
var maxQuantity = HKQuantity(unit: .gram(), doubleValue: 99)
Pods: Add Extra Insulin on Insertion¶
The default value is 0.0 U of extra insulin. If you use this customization, start with a small number and work your way up. If you are coming from manual podding and routinely gave yourself an extra bolus with your PDM at pod change time, you may not need nearly as much with Loop - be conservative.
Note that Loop does not include the amount of insulin in the prime or insertion steps in your IOB. The pod reports every pulse that it delivers to Loop. If you look in the Pod Settings insulin delivered row, that is the total delivered by the pod minus the (prime plus insertion) amounts. The only way to know that you successfully made this change is to count the clicks. Normal insertion is 0.5 U (0.5 U / 0.05 U per click = 10 clicks). So if you add 0.35 U to the "extra" value, you should get 0.35 / 0.05 = 7 extra clicks. In other words, 17 total clicks after you press insert.
This code change is found in one location for Eros Pods (called Omnipod throughout the app) and DASH Pods (called Omnipod Dash throughout the app). I tend to change both files, but if you're only using one kind of pod, that is really not necessary.
let cannulaInsertionUnitsExtra
- Module: OmniBLE (DASH) or OmniKit (Eros)
- DASH or Eros Pod (Loop 3 only)
- Folder: OmniBLE/OmniBLE/OmnipodCommon (DASH)
- Folder: OmniKit/OmniKit/OmnipodCommon (Eros)
- File: Pod.swift, Line 82 (DASH); Line 87 (Eros);
- Loop 2.2.x: Eros Pod (still configured in rileylink_ios - use Key_Phrase)
Code Before Modification
public static let cannulaInsertionUnitsExtra = 0.0 // edit to add a fixed additional amount of insulin during cannula insertion
Code After Modification to add 0.35 U
public static let cannulaInsertionUnitsExtra = 0.35 // edit to add a fixed additional amount of insulin during cannula insertion
Modify the Guardrails¶
The Therapy Setting Guardrails are for Loop 3 only.
Glucose Guardrails¶
If you build Loop 3 over a version of Loop 2.2.x or FreeAPS where the Correction Range is lower than the default value of 87 mg/dL (4.8 mmol/L), your app requires you to satisfy the new guardrail before you can save that Therapy Setting when you onboard.
Guardrail(absoluteBounds:
- Module: LoopKit
- Folder: LoopKit/Extensions
- File: Guardrail+Settings.swift
- Line: 12 for suspendThreshold
- Line: 26 for correctionRange
Code Before Modification
static let suspendThreshold = Guardrail(absoluteBounds: 67...110, recommendedBounds: 74...80, unit: .milligramsPerDeciliter, startingSuggestion: 80)
and
static let correctionRange = Guardrail(absoluteBounds: 87...180, recommendedBounds: 100...115, unit: .milligramsPerDeciliter, startingSuggestion: 100)
Modify the 67 for suspendThreshold or 87 for correctionRange to the desired value. Loop automatically converts from mg/dL. So you must enter values reasonable for mg/dL (18 times higher than for mmol/L).
Modify Guardrails for Insulin Sensitivity Factor (ISF)¶
Similar to the instructions for glucose guardrails above, but use this Key_Phrase
and modify the absoluteBounds row, next line.
static let insulinSensitivity = Guardrail(
- Module: LoopKit
- Folder: LoopKit/Extensions
- File: Guardrail+Settings.swift, line: 81
Modify Guardrails for Carb Ratio (CR)¶
Similar to the instructions for glucose guardrails above, but use this Key_Phrase
and modify the absoluteBounds row, next line.
static let carbRatio = Guardrail(
- Module: LoopKit
- Folder: LoopKit/Extensions
- File: Guardrail+Settings.swift, line: 88
Adjust Future Carbs Time Interval¶
Loop 3 limits the future time change allowed to 1 hour.
cell.datePicker.maximumDate = date.addingTimeInterval
- Module: Loop
- Folder: Loop/Loop/View Controllers
- File:CarbEntryViewController.swift, Line 438
Default shown below (for maximum and minimum):
Code Before Modification
cell.datePicker.maximumDate = date.addingTimeInterval(.hours(1))
cell.datePicker.minimumDate = date.addingTimeInterval(.hours(-12))
Change the maximumDate to the number of hours in the future you desire. Remember that Loop may increase insulin dosing for future carbs - make sure that they actually arrive.
The minimumDate is how far back in the past you can modify time. The default is 12 hours in the past.
Adjust the Watch Crown Sensitivity¶
The rate of change of the carb and bolus entry pickers when using the digital crown can be altered as can the rotation required to confirm a bolus on the watch. If you are running an older series watch - you may want to make these customizations. When I switched from Series 3 to Series 7 watch - it was amazing. I got a graph on the main watch screen I didn't even know existed and the bolus acceptance was a breeze!
There are a number of places where you need to make changes (2 for sensitivity and 2 for bolus confirmation for Loop 2.2.x), so walk though them one at a time. For the Watch Crown Sensitivity
, the 1/24 value is the ratio of rotations of the crown to the amount of change in the value. Changing it to 1/12 would mean that half as many turns would be needed for the same amount of carb or bolus entry.
- The Loop 2.2.x customizations are throughly tested by many users.
- The Loop 3 customization is provided from code inspection and one test - use with care.
Loop 2.2.x Sensitivity¶
let rotationsPerIncrement
- Folder: Loop/WatchApp Extension/Controllers
- File: AddCarbsInterfaceController.swift, Line: 249
- Initial Value: 1/24; try 1/12 to increase change in picker value for a given motion
let rotationsPerValue
- Folder: Loop/WatchApp Extension/Controllers
- File: BolusInterfaceController.swift, Line: 191
- Initial Value: 1/24; try 1/12 to increase change in picker value for a given motion
Loop 2.2.x Bolus Confirmation¶
In order to reduce the amount the user has to spin the watch crown to confirm a bolus, there are 3 numbers on 2 lines that must be modified. You will be working in the same file you just used to modify the watch sensitivity to adjusting the bolus amount, BolusInterfaceController.swift.
For example to change rotation required to 70% of the default, change 1.0 to 0.7 in 3 places on those 2 lines. This Key_Phrase
returns 3 lines, the second 2 of which are the ones in that file where the change is required:
abs(accumulatedRotation)
- Folder: Loop/WatchApp Extension/Controllers
- File: BolusInterfaceController.swift, Lines: 311 and 360
- Initial Value: 1.0; try 0.7 to decrease how much is needed to confirm bolus
Loop 3 Digital Crown Adjustments¶
These are new instructions and the user should take care - and please report back if you have problems.
First - try it with no customization. Then make small changes.
This key phrase will indicate three different files in the same folder as shown in the graphic below - you can adjust each in turn as you desire. When you click on the line, the quantity you change is a few lines below where you find the Key_Phrase
, except for the CarbAndDateInput file.
.digitalCrownRotation
- Module: Loop
- Folder: Loop/WatchApp Extension/Views/Carb Entry & Bolus
Modify Bolus Confirmation Motion¶
- File: BolusConfirmationView.swift, line 59
- Initial Value for
scalingRotationBy
is 4 - Decrease to require less motion to confirm bolus (use whole numbers only), start with 3
Modify Bolus Picker Sensitivity¶
- File: BolusInput.swift, line 53
- Initial Value for
rotationsPerIncrement
is 1/24 - A change to 1/12 increases the change in picker value for a given motion
Modify Carb and Time Picker Sensitivity¶
- File: CarbAndDateInput.swift, line 68
- Initial Value for
rotationsPerIncrement
is 1/24 - A change to 1/12 increases the change in picker value for a given motion
Expiration Notification Customization¶
An expiration notification feature has been added to Loop. You get a notification when you open the Loop app to alert you that the expiration is approaching. (Not available with version v2.2.4 and earlier.)
- Read Loop App Expiration Notification to see the expiration reminder
- Read Loop App Expiration Date if you have an older version of Loop
If you prefer a different notification time and frequency, there are two lines you can modify:
- Module: Loop
- Folder: Loop/Managers
- File: ProfileExpirationAlerter.swift
- Line 16: modify how long before expiration you get the FIRST notification
- Line 28: modify how frequently you will be notified
expirationAlertWindow: TimeInterval
minimumTimeBetweenAlerts: TimeInterval
Default code for line 16:
static let expirationAlertWindow: TimeInterval = .days(20)
Example modifications to First Notification:
- 30 days: change
.days(20)
to.days(30)
- 12 hours: change
.days(20)
to.hours(12)
Default code for line 28:
let minimumTimeBetweenAlerts: TimeInterval = timeUntilExpiration > .hours(24) ? .days(2) : .hours(1)
Modify Frequency of Repeated Notifications (Three Values):
- This phrase:
> .hours(24) ? .days(2) : .hours(1)
- Rewritten as:
> Time_A ? Frequency_A : Frequency_B
, means:- Use Frequency_A if there is more time between now and the expiration date than Time_A
- Use Frequency_B if there is less time between now and the expiration date than Time_A
You can enter Time or Frequency as .days(value)
, .hours(value)
or .minutes(value)
.
Free App Users:
An example change that a Free Loop App user (who has to build once a week) might choose is:
> .hours(4) ? .days(10) : .hours(2)
.hours(12)
on line 16, they would get notified at 12 hours, 4 hours and 2 hours before expiration on the day of expiration and only when the app is opened. Since you'll be building once a week, you can play around with these values until you are happy.
Exponential Insulin Curve¶
Enable Child Model¶
Loop 3, by default, does not include the concept of child versus adult for rapid-acting insulin, i.e., Humalog, Novalog and Apidra.
- The child model can be enabled following the directions in Build-Time Features, adding ADULT_CHILD_INSULIN_MODEL_SELECTION_ENABLED to the LoopConfigOverride.xcconfig file and rebuilding
- Insulin Model is then found in the Therapy Setting section of Loop 3 with Adult selected by default
- Insulin Type continues to be associated with the pump and can be modified in the Pump Settings screen
Insulin Model Customization¶
Each exponential model has 3 parameters that can be adjusted:
- actionDuration: Duration of insulin activity (minutes)
- peakActivity: Peak of insulin activity (minutes)
- delay: Delay before insulin begins to acts after delivery starts (minutes)
Please read the nitty-gritty discussion that went into the development of the "exponential insulin models" in this GitHub Issue Comment.
If you wish to customize these values, please make sure you know what you are doing. This is not a modification recommended for Loop novices.
MARK: - Model generation
- Module: LoopKit
- Loop 3
- Folder: LoopKit/LoopKit/Insulin/ << NOTE new location
- File: ExponentialInsulinModelPreset.swift
- Lines:
- actionDuration (19 to 32)
- peakActivity (34 to 47)
- delay (49 to 62)
- Loop 2.2.x
- Folder: Loop/LoopCore/Insulin
- File: ExponentialInsulinModelPreset.swift
- Lines:
- actionDuration (20 to 29)
- peakActivity (31 to 40)
- effectDelay (42 to 51)
This Loop 3 table of default values is provided for convenience. The times are all in minutes.
Model | DIA | Peak | Delay |
---|---|---|---|
rapidActingAdult | 360 | 75 | 10 |
rapidActingChild | 360 | 65 | 10 |
fiasp | 360 | 55 | 10 |
lyumjev | 360 | 55 | 10 |
afrezza | 300 | 29 | 10 |
Loop Logo¶
Mac-Xcode Instructions
This can be done with GitHub but the instructions might need to be adjusted for that case.
If you want an app logo other than the default green circle for your Loop app, you can easily customize this. To make it easy to generate the correct sizes of icons, you can use a site like appicon.build or appicon.co and just drag and drop your source image. The source image needs to be 1024 pixels x 1024 pixels. The site will email you a zip file or automatically download a set of files. Highlight and copy the contents of the Appicon.appiconset that you are sent, including the Contents.json file
Use Finder to Navigate to the LoopWorkspace folder. These instructions assume you used the Build Select Script - if your files are in a different folder, make the appropriate adjustment.
For Loop 2.2.x:
- Use Finder to navigate to Downloads / BuildLoop and open the folder with the most recent date (e.g., Loop-Master-211006-0524)
- Double-click on the LoopWorkspace folder
- Double-click on the AdditionaAssets.xcassets folder
- Double-click on the CustomLoopIcon.appiconset folder
- Delete the contents of the CustomLoopIcon.appiconset folder and copy/paste your new images and Contents.json file.
- Rebuild your app
For Loop 3:
- Make sure Xcode is closed
- Use Finder to navigate to Downloads / BuildLoop and open the folder with the most recent date (e.g., Loop-230114-1153)
- Double-click on the LoopWorkspace folder
- Double-click on the OverrideAssetsLoop.xcassets folder
- Double-click on the AppIcon.appiconset folder
- Delete the contents of the Appicon.appiconset and copy/paste your new images and Contents.json file.
- Rebuild your app
You may see a yellow warning that there are “unassigned children” depending on the images the app icon generator tool produced. The unassigned children alert will not prevent your app from building, it’s simply because there are more sizes of images than Loop app uses. You can just leave the unassigned children alone (wow...how often do you get to say that phrase?).
And now you'll be the proud new owner of a custom Loop icon.
Additional Customizations for Loop 3¶
If you want to add these customizations: CustomTypeOne LoopPatches and clients for xDrip4iOS and GlucoseDirect, which assist those using Libre sensors, you can add them yourself (with either Mac-Xcode or GitHub browser build method) or use a prepared fork that already contains them.
These customizations are only for Loop 3:
- Some are already added to the released version of Loop in a fork of LoopWorkspace for your convenience, Loop and Learn: Loop with Patches
Open a Terminal in LoopWorkspace Folder¶
Refer to the graphic below. The Downloads folder in Finder is highlighted on the upper left. The full path to Loop.xcworkspace is highlighted along the bottom. Double clicking on that file opens Xcode; but to apply customizations, you need to type commands in the terminal.
- Open Finder
- Navigate to Downloads/BuildLoop and look for your download by name and date
- Open that folder, for example, Downloads/BuildLoop/Loop-220803-1145
- Find the LoopWorkspace folder icon (dashed-blue rectangle)
- Hold down the CTRL key and click (or right-click) LoopWorkspace
- A menu appears - select
New Terminal at Folder
(near the bottom of the list)
This new terminal window is ready to accept commands as needed when the instructions say to start a terminal in the LoopWorkspace folder.
To confirm you are in the correct location, type pwd
and return in the terminal. The response must end in LoopWorkspace. For example, using the graphic below, the response to pwd
should be similar to:
/Users/marion/Downloads/BuildLoop/Loop-20220803-1145/LoopWorkspace
Custom Type One LoopPatches¶
Several items have been consolidated into a set of patches found at CustomTypeOne/LoopPatches. These patches only work with Loop 3 (main branch).
If you are using a development branch of Loop, you need the dev branch of LoopPatches. Note - even the dev branch of LoopPatches takes time to update for some changes to the Loop-dev code. CustomTypeOne/LoopPatches for dev branch
Please read the LoopPatches documentation, follow the installation directions carefully and then test any patch that you enable - every time you build. These patches don't have the nice guardrails found in Loop 3.
The CustomTypeOne LoopPatches are included in Loop and Learn: Loop with Patches.
Add Libre App to Loop Phone¶
This method only works for Loop 3 and only for some Libre sensors. The US versions for Libre 2 cannot be read with an iPhone.
There are several options for code that will read the raw Libre values and convert them into glucose readings. You must do your own research to decide which code to use. Be aware that you must perform careful calibrations to maintain accurate glucose estimates.
These are the Libre iOS app options.
- xDrip4iOS: Documentation
- Check to see if your sensor is compatible
- To use this code with Loop, you must "build it yourself" with the same developer ID as you use with Loop
- You can use the Loop and Learn: Build Select Script and choose Option 2: Build Related Apps and then select xDrip4iOS
- If you use the TestFlight installation method with someone else's apple developer id, you will need an internet connection to Loop
- GlucoseDirect: README file on github repository
- To use this code with Loop, you must "build it yourself" with the same developer ID as you use with Loop
- You can use the Loop and Learn: Build Select Script and choose Option 2: Build Related Apps and then select GlucoseDirect
- If you use the TestFlight installation method with someone else's apple developer id, you will need an internet connection to Loop
- To use this code with Loop, you must "build it yourself" with the same developer ID as you use with Loop
- LibreTransmitter for Loop: README file on github repository
- LibreTransmitter is incorporated into Loop directly, so no separate app is required
- Refer to LibreTransmitter
Once you have chosen the desired app, you need to install it on your Loop phone using the same developer ID as was used for the Loop app and then you must modify the Loop 3 code that you previously downloaded or use Loop and Learn: Loop Customization.
Modify Loop to use Libre¶
The Loop and Learn: Loop with Patches version of Loop has both xDrip4iOS and GlucoseDirect clients. If you choose to add them yourself and not use that fork, then follow the steps below.
For your selected app to read the Libre, you must also add a client to Loop 3 to interface with the "reader" app. You only need to add the client for the app you've chosen for accessing your Libre sensor. However, you may find watching the video for GlucoseDirectClient and reading the step-by-step instructions for xdrip-client-swift or LibreTransmitter may together give you a better idea how to incorporate your preferred app with Loop 3.
Add a client that interfaces with xDrip4iOS:
- Add xdrip-client-swift to Loop 3
- Note - there are extra details visible when you click on the black arrow icons in this file
- zulipchat converstation
Add a client that interfaces with GlucoseDirect:
- Add GlucoseDirectClient
- zulipchat conversation
- The instructions are in the video on the GlucoseDirectClient repo page
LibreTransmitter¶
Add LibreTransmitter to Loop as a plugin:
- LibreTransmitter for Loop: README file on github repository
- LibreTransmitter is incorporated into Loop directly, so there not a separate app to be installed
- zulipchat conversation
- There is a development branch, libre, that has this incorporated
- See BuildLoopDev Script
Limit Loop for Faster CGM¶
Loop 3 enables higher rates of CGM updates. One consequence of this can be increased usage of pump batteries. This can contribute to pod faults with Eros pods or even DASH pods when using a Libre sensor with 1-minute CGM updates. Medtronic pumps are very unhappy with faster Loop cycles and should not be subjected to this.
This modification limits the period for Loop cycles to 4.8 minutes or longer. See also Loop and Learn: Single Customization List.
Meant for Libre Users
This customization is suggested for Libre Users who need to limit how frequently Loop modifies dosing commands to preserve pod batteries.
The Loop 3 code was modified when adding support for DASH pods. The DASH pods have a 3-minute heartbeat and it was discovered that with Dexcom (5-minute update rate) and DASH, the Loop could switch to a DASH heartbeat and not be triggered by the next CGM reading. Loop works much better when each Loop cycle is triggered by the CGM.
The preferred solution is to have the CGM manager decide when to send updated glucose values to Loop.
let timeSinceLastLoop
- Folder: Loop/Loop/Managers/
- File: LoopDataManager.swift, Line: 841
The Key_Phrase gets you near where you will insert new code.
Code Before Modification
The line above the Key_Phrase is:
if let lastLoopCompleted = self.lastLoopCompleted {
You can copy the lines below and replace the one line above with this new code.
Code After Modification
// Limit Loop frequency to 4.8 minutes
if let lastLoopCompleted = self.lastLoopCompleted, Date().timeIntervalSince(lastLoopCompleted) < TimeInterval(minutes: 4.8) {
self.logger.default("Skipping loop attempt as last loop completed at %{public}@", String(describing: lastLoopCompleted))
return
} else if let lastLoopCompleted = self.lastLoopCompleted {
Folders and Icons¶
The folders listed in the code customization steps are the actual directory names as stored on your computer. However, a shortened name is used for some folders when being displayed as icons in Xcode. Some people prefer to search through the folder icons to find a file instead of using the Find in Workspace
feature.
In the graphic below, the user searched for an item found for both Eros and DASH pods (in two different files). The top part of the graphic shows the result of the search with user clicking on one instance. On the right side of the top graphic (highlighted by red rectangle) is the name of the selected file on the computer with the full directory name.
- Inset 1: User clicked on the folder icon (highlighted by red square) to see the list of icons for folders included in the LoopWorkspace
- Inset 2: User opens folders under RileyLink icon to open OmniKit, then OmnipodCommon to find the Pod.swift file (NOTE - the Eros information is in a different Module now, OmniKit, but the graphic has not been updated.)
These folder icon names are different from the directory names on the computer:
Folder Icon Name | Directory Name | |
---|---|---|
ShareClient | dexcom-share-client-swift | |
RileyLink | rileylink_ios | |
Amplitude | Amplitude-iOS |
All other icons and directory names match.