PreferencesEditorStateModel.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. import Foundation
  2. import SwiftUI
  3. extension PreferencesEditor {
  4. final class StateModel: BaseStateModel<Provider>, PreferencesSettable { private(set) var preferences = Preferences()
  5. @Published var unitsIndex = 1
  6. @Published var allowAnnouncements = false
  7. @Published var insulinReqFraction: Decimal = 0.7
  8. @Published var skipBolusScreenAfterCarbs = false
  9. @Published var sections: [FieldSection] = []
  10. override func subscribe() {
  11. preferences = provider.preferences
  12. subscribeSetting(\.allowAnnouncements, on: $allowAnnouncements) { allowAnnouncements = $0 }
  13. subscribeSetting(\.insulinReqFraction, on: $insulinReqFraction) { insulinReqFraction = $0 }
  14. subscribeSetting(\.skipBolusScreenAfterCarbs, on: $skipBolusScreenAfterCarbs) { skipBolusScreenAfterCarbs = $0 }
  15. subscribeSetting(\.units, on: $unitsIndex.map { $0 == 0 ? GlucoseUnits.mgdL : .mmolL }) {
  16. unitsIndex = $0 == .mgdL ? 0 : 1
  17. } didSet: { [weak self] _ in
  18. self?.provider.migrateUnits()
  19. }
  20. // MARK: - Main fields
  21. let mainFields = [
  22. Field(
  23. displayName: "Insulin curve",
  24. type: .insulinCurve(keypath: \.curve),
  25. infoText: "Insulin curve info",
  26. settable: self
  27. ),
  28. Field(
  29. displayName: "Max IOB",
  30. type: .decimal(keypath: \.maxIOB),
  31. infoText: NSLocalizedString(
  32. "Max IOB is the maximum amount of insulin on board from all sources – both basal (or SMB correction) and bolus insulin – that your loop is allowed to accumulate to treat higher-than-target BG. Unlike the other two OpenAPS safety settings (max_daily_safety_multiplier and current_basal_safety_multiplier), max_iob is set as a fixed number of units of insulin. As of now manual boluses are NOT limited by this setting. \n\n To test your basal rates during nighttime, you can modify the Max IOB setting to zero while in Closed Loop. This will enable low glucose suspend mode while testing your basal rates settings\n\n(Tip from https://www.loopandlearn.org/freeaps-x/#open-loop).",
  33. comment: "Max IOB"
  34. ),
  35. settable: self
  36. ),
  37. Field(
  38. displayName: "Max COB",
  39. type: .decimal(keypath: \.maxCOB),
  40. infoText: NSLocalizedString(
  41. "This defaults maxCOB to 120 because that’s the most a typical body can absorb over 4 hours. (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120. Essentially, this just limits AMA as a safety cap against weird COB calculations due to fluky data.)",
  42. comment: "Max COB"
  43. ),
  44. settable: self
  45. ),
  46. Field(
  47. displayName: "Max Daily Safety Multiplier",
  48. type: .decimal(keypath: \.maxDailySafetyMultiplier),
  49. infoText: NSLocalizedString(
  50. "This is an important OpenAPS safety limit. The default setting (which is unlikely to need adjusting) is 3. This means that OpenAPS will never be allowed to set a temporary basal rate that is more than 3x the highest hourly basal rate programmed in a user’s pump, or, if enabled, determined by autotune.",
  51. comment: "Max Daily Safety Multiplier"
  52. ),
  53. settable: self
  54. ),
  55. Field(
  56. displayName: "Current Basal Safety Multiplier",
  57. type: .decimal(keypath: \.currentBasalSafetyMultiplier),
  58. infoText: NSLocalizedString(
  59. "This is another important OpenAPS safety limit. The default setting (which is also unlikely to need adjusting) is 4. This means that OpenAPS will never be allowed to set a temporary basal rate that is more than 4x the current hourly basal rate programmed in a user’s pump, or, if enabled, determined by autotune.",
  60. comment: "Current Basal Safety Multiplier"
  61. ),
  62. settable: self
  63. ),
  64. Field(
  65. displayName: "Autosens Max",
  66. type: .decimal(keypath: \.autosensMax),
  67. infoText: NSLocalizedString(
  68. "This is a multiplier cap for autosens (and autotune) to set a 20% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.",
  69. comment: "Autosens Max"
  70. ),
  71. settable: self
  72. ),
  73. Field(
  74. displayName: "Autosens Min",
  75. type: .decimal(keypath: \.autosensMin),
  76. infoText: NSLocalizedString(
  77. "The other side of the autosens safety limits, putting a cap on how low autosens can adjust basals, and how high it can adjust ISF and BG targets.",
  78. comment: "Autosens Min"
  79. ),
  80. settable: self
  81. )
  82. ]
  83. // MARK: - SMB fields
  84. let smbFields = [
  85. Field(
  86. displayName: "Enable SMB Always",
  87. type: .boolean(keypath: \.enableSMBAlways),
  88. infoText: NSLocalizedString(
  89. "Defaults to false. When true, always enable supermicrobolus (unless disabled by high temptarget).",
  90. comment: "Enable SMB Always"
  91. ),
  92. settable: self
  93. ),
  94. Field(
  95. displayName: "Enable SMB With COB",
  96. type: .boolean(keypath: \.enableSMBWithCOB),
  97. infoText: NSLocalizedString(
  98. "This enables supermicrobolus (SMB) while carbs on board (COB) are positive.",
  99. comment: "Enable SMB With COB"
  100. ),
  101. settable: self
  102. ),
  103. Field(
  104. displayName: "Enable SMB With Temptarget",
  105. type: .boolean(keypath: \.enableSMBWithTemptarget),
  106. infoText: NSLocalizedString(
  107. "This enables supermicrobolus (SMB) with eating soon / low temp targets. With this feature enabled, any temporary target below 100mg/dL, such as a temp target of 99 (or 80, the typical eating soon target) will enable SMB.",
  108. comment: "Enable SMB With Temptarget"
  109. ),
  110. settable: self
  111. ),
  112. Field(
  113. displayName: "Enable SMB After Carbs",
  114. type: .boolean(keypath: \.enableSMBAfterCarbs),
  115. infoText: NSLocalizedString(
  116. "Defaults to false. When true, enables supermicrobolus (SMB) for 6h after carbs, even with 0 carbs on board (COB).",
  117. comment: "Enable SMB After Carbs"
  118. ),
  119. settable: self
  120. ),
  121. Field(
  122. displayName: "Allow SMB With High Temptarget",
  123. type: .boolean(keypath: \.allowSMBWithHighTemptarget),
  124. infoText: NSLocalizedString(
  125. "Defaults to false. When true, allows supermicrobolus (if otherwise enabled) even with high temp targets.",
  126. comment: "Allow SMB With High Temptarget"
  127. ),
  128. settable: self
  129. ),
  130. Field(
  131. displayName: "Enable UAM",
  132. type: .boolean(keypath: \.enableUAM),
  133. infoText: NSLocalizedString(
  134. "With this option enabled, the SMB algorithm can recognize unannounced meals. This is helpful, if you forget to tell FreeAPS X about your carbs or estimate your carbs wrong and the amount of entered carbs is wrong or if a meal with lots of fat and protein has a longer duration than expected. Without any carb entry, UAM can recognize fast glucose increasments caused by carbs, adrenaline, etc, and tries to adjust it with SMBs. This also works the opposite way: if there is a fast glucose decreasement, it can stop SMBs earlier.",
  135. comment: "Enable UAM"
  136. ),
  137. settable: self
  138. ),
  139. Field(
  140. displayName: "Max SMB Basal Minutes",
  141. type: .decimal(keypath: \.maxSMBBasalMinutes),
  142. infoText: NSLocalizedString(
  143. "Defaults to start at 30. This is the maximum minutes of basal that can be delivered as a single SMB with uncovered COB. This gives the ability to make SMB more aggressive if you choose. It is recommended that the value is set to start at 30, in line with the default, and if you choose to increase this value, do so in no more than 15 minute increments, keeping a close eye on the effects of the changes. It is not recommended to set this value higher than 90 mins, as this may affect the ability for the algorithm to safely zero temp. It is also recommended that pushover is used when setting the value to be greater than default, so that alerts are generated for any predicted lows or highs.",
  144. comment: "Max SMB Basal Minutes"
  145. ),
  146. settable: self
  147. ),
  148. Field(
  149. displayName: "Max UAM SMB Basal Minutes",
  150. type: .decimal(keypath: \.maxUAMSMBBasalMinutes),
  151. infoText: NSLocalizedString(
  152. "Defaults to start at 30. This is the maximum minutes of basal that can be delivered by UAM as a single SMB when IOB exceeds COB. This gives the ability to make UAM more or less aggressive if you choose. It is recommended that the value is set to start at 30, in line with the default, and if you choose to increase this value, do so in no more than 15 minute increments, keeping a close eye on the effects of the changes. Reducing the value will cause UAM to dose less insulin for each SMB. It is not recommended to set this value higher than 60 mins, as this may affect the ability for the algorithm to safely zero temp. It is also recommended that pushover is used when setting the value to be greater than default, so that alerts are generated for any predicted lows or highs.",
  153. comment: "Max UAM SMB Basal Minutes"
  154. ),
  155. settable: self
  156. ),
  157. Field(
  158. displayName: "SMB Interval",
  159. type: .decimal(keypath: \.smbInterval),
  160. infoText: NSLocalizedString("Minimum duration in minutes between two enacted SMBs", comment: "SMB Interval"),
  161. settable: self
  162. ),
  163. Field(
  164. displayName: "Bolus Increment",
  165. type: .decimal(keypath: \.bolusIncrement),
  166. infoText: NSLocalizedString("Smallest possible bolus amount", comment: "Bolus Increment"),
  167. settable: self
  168. )
  169. ]
  170. // MARK: - Targets fields
  171. let targetSettings = [
  172. Field(
  173. displayName: "High Temptarget Raises Sensitivity",
  174. type: .boolean(keypath: \.highTemptargetRaisesSensitivity),
  175. infoText: NSLocalizedString(
  176. "Defaults to false. When set to true, raises sensitivity (lower sensitivity ratio) for temp targets set to >= 111. Synonym for exercise_mode. The higher your temp target above 110 will result in more sensitive (lower) ratios, e.g., temp target of 120 results in sensitivity ratio of 0.75, while 140 results in 0.6 (with default halfBasalTarget of 160).",
  177. comment: "High Temptarget Raises Sensitivity"
  178. ),
  179. settable: self
  180. ),
  181. Field(
  182. displayName: "Low Temptarget Lowers Sensitivity",
  183. type: .boolean(keypath: \.lowTemptargetLowersSensitivity),
  184. infoText: NSLocalizedString(
  185. "Defaults to false. When set to true, can lower sensitivity (higher sensitivity ratio) for temptargets <= 99. The lower your temp target below 100 will result in less sensitive (higher) ratios, e.g., temp target of 95 results in sensitivity ratio of 1.09, while 85 results in 1.33 (with default halfBasalTarget of 160).",
  186. comment: "Low Temptarget Lowers Sensitivity"
  187. ),
  188. settable: self
  189. ),
  190. Field(
  191. displayName: "Sensitivity Raises Target",
  192. type: .boolean(keypath: \.sensitivityRaisesTarget),
  193. infoText: NSLocalizedString(
  194. "When true, raises BG target when autosens detects sensitivity",
  195. comment: "Sensitivity Raises Target"
  196. ),
  197. settable: self
  198. ),
  199. Field(
  200. displayName: "Resistance Lowers Target",
  201. type: .boolean(keypath: \.resistanceLowersTarget),
  202. infoText: NSLocalizedString(
  203. "Defaults to false. When true, will lower BG target when autosens detects resistance",
  204. comment: "Resistance Lowers Target"
  205. ),
  206. settable: self
  207. ),
  208. Field(
  209. displayName: "Advanced Target Adjustments",
  210. type: .boolean(keypath: \.advTargetAdjustments),
  211. infoText: NSLocalizedString(
  212. "This feature was previously enabled by default but will now default to false (will NOT be enabled automatically) in oref0 0.6.0 and beyond. (There is no need for this with 0.6.0). This feature lowers oref0’s target BG automatically when current BG and eventualBG are high. This helps prevent and mitigate high BG, but automatically switches to low-temping to ensure that BG comes down smoothly toward your actual target. If you find this behavior too aggressive, you can disable this feature. If you do so, please let us know so we can better understand what settings work best for everyone.",
  213. comment: "Advanced Target Adjustments"
  214. ),
  215. settable: self
  216. ),
  217. Field(
  218. displayName: "Exercise Mode",
  219. type: .boolean(keypath: \.exerciseMode),
  220. infoText: NSLocalizedString(
  221. "Defaults to false. When true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. Synonym for high_temptarget_raises_sensitivity",
  222. comment: "Exercise Mode"
  223. ),
  224. settable: self
  225. ),
  226. Field(
  227. displayName: "Half Basal Exercise Target",
  228. type: .decimal(keypath: \.halfBasalExerciseTarget),
  229. infoText: NSLocalizedString(
  230. "Set to a number, e.g. 160, which means when temp target is 160 mg/dL and exercise_mode=true, run 50% basal at this level (120 = 75%; 140 = 60%). This can be adjusted, to give you more control over your exercise modes.",
  231. comment: "Half Basal Exercise Target"
  232. ),
  233. settable: self
  234. ),
  235. Field(
  236. displayName: "Wide BG Target Range",
  237. type: .boolean(keypath: \.wideBGTargetRange),
  238. infoText: NSLocalizedString(
  239. "Defaults to false, which means by default only the low end of the pump’s BG target range is used as OpenAPS target. This is a safety feature to prevent too-wide targets and less-optimal outcomes. Therefore the higher end of the target range is used only for avoiding bolus wizard overcorrections. Use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs.",
  240. comment: "Wide BG Target Range"
  241. ),
  242. settable: self
  243. )
  244. ]
  245. // MARK: - Other fields
  246. let otherSettings = [
  247. Field(
  248. displayName: "Rewind Resets Autosens",
  249. type: .boolean(keypath: \.rewindResetsAutosens),
  250. infoText: NSLocalizedString(
  251. "This feature, enabled by default, resets the autosens ratio to neutral when you rewind your pump, on the assumption that this corresponds to a probable site change. Autosens will begin learning sensitivity anew from the time of the rewind, which may take up to 6 hours. If you usually rewind your pump independently of site changes, you may want to consider disabling this feature.",
  252. comment: "Rewind Resets Autosens"
  253. ),
  254. settable: self
  255. ),
  256. Field(
  257. displayName: "Use Custom Peak Time",
  258. type: .boolean(keypath: \.useCustomPeakTime),
  259. infoText: NSLocalizedString(
  260. "Defaults to false. Setting to true allows changing insulinPeakTime", comment: "Use Custom Peak Time"
  261. ),
  262. settable: self
  263. ),
  264. Field(
  265. displayName: "Insulin Peak Time",
  266. type: .decimal(keypath: \.insulinPeakTime),
  267. infoText: NSLocalizedString(
  268. "Time of maximum blood glucose lowering effect of insulin, in minutes. Beware: Oref assumes for ultra-rapid (Lyumjev) & rapid-acting (Fiasp) curves minimal (35 & 50 min) and maximal (100 & 120 min) applicable insulinPeakTimes. Using a custom insulinPeakTime outside these bounds will result in issues with FreeAPS-X, longer loop calculations and possible red loops.",
  269. comment: "Insulin Peak Time"
  270. ),
  271. settable: self
  272. ),
  273. // Field(
  274. // displayName: "Carbs Req Threshold",
  275. // type: .decimal(keypath: \.carbsReqThreshold),
  276. // infoText: NSLocalizedString(
  277. // "Grams of carbsReq to trigger a pushover. Defaults to 1 (for 1 gram of carbohydrate). Can be increased if you only want to get Pushover for carbsReq at X threshold.",
  278. // comment: "Carbs Req Threshold"
  279. // ),
  280. // settable: self
  281. // ),
  282. Field(
  283. displayName: "Skip Neutral Temps",
  284. type: .boolean(keypath: \.skipNeutralTemps),
  285. infoText: NSLocalizedString(
  286. "Defaults to false, so that FreeAPS X will set temps whenever it can, so it will be easier to see if the system is working, even when you are offline. This means FreeAPS X will set a “neutral” temp (same as your default basal) if no adjustments are needed. This is an old setting for OpenAPS to have the options to minimise sounds and notifications from the 'rig', that may wake you up during the night.",
  287. comment: "Skip Neutral Temps"
  288. ),
  289. settable: self
  290. ),
  291. Field(
  292. displayName: "Unsuspend If No Temp",
  293. type: .boolean(keypath: \.unsuspendIfNoTemp),
  294. infoText: NSLocalizedString(
  295. "Many people occasionally forget to resume / unsuspend their pump after reconnecting it. If you’re one of them, and you are willing to reliably set a zero temp basal whenever suspending and disconnecting your pump, this feature has your back. If enabled, it will automatically resume / unsuspend the pump if you forget to do so before your zero temp expires. As long as the zero temp is still running, it will leave the pump suspended.",
  296. comment: "Unsuspend If No Temp"
  297. ),
  298. settable: self
  299. ),
  300. Field(
  301. displayName: "Suspend Zeros IOB",
  302. type: .boolean(keypath: \.suspendZerosIOB),
  303. infoText: NSLocalizedString(
  304. "Default is false. Any existing temp basals during times the pump was suspended will be deleted and 0 temp basals to negate the profile basal rates during times pump is suspended will be added.",
  305. comment: "Suspend Zeros IOB"
  306. ),
  307. settable: self
  308. ),
  309. Field(
  310. displayName: "Bolus Snooze DIA Divisor",
  311. type: .decimal(keypath: \.bolusSnoozeDIADivisor),
  312. infoText: NSLocalizedString(
  313. "Bolus snooze is enacted after you do a meal bolus, so the loop won’t counteract with low temps when you’ve just eaten. The example here and default is 2; so a 3 hour DIA means that bolus snooze will be gradually phased out over 1.5 hours (3DIA/2).",
  314. comment: "Bolus Snooze DIA Divisor"
  315. ),
  316. settable: self
  317. ),
  318. Field(
  319. displayName: "Min 5m Carbimpact",
  320. type: .decimal(keypath: \.min5mCarbimpact),
  321. infoText: NSLocalizedString(
  322. "This is a setting for default carb absorption impact per 5 minutes. The default is an expected 8 mg/dL/5min. This affects how fast COB is decayed in situations when carb absorption is not visible in BG deviations. The default of 8 mg/dL/5min corresponds to a minimum carb absorption rate of 24g/hr at a CSF of 4 mg/dL/g.",
  323. comment: "Min 5m Carbimpact"
  324. ),
  325. settable: self
  326. ),
  327. Field(
  328. displayName: "Autotune ISF Adjustment Fraction",
  329. type: .decimal(keypath: \.autotuneISFAdjustmentFraction),
  330. infoText: NSLocalizedString(
  331. "The default of 0.5 for this value keeps autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF.",
  332. comment: "Autotune ISF Adjustment Fraction"
  333. ),
  334. settable: self
  335. ),
  336. Field(
  337. displayName: "Remaining Carbs Fraction",
  338. type: .decimal(keypath: \.remainingCarbsFraction),
  339. infoText: NSLocalizedString(
  340. "This is the fraction of carbs we’ll assume will absorb over 4h if we don’t yet see carb absorption.",
  341. comment: "Remaining Carbs Fraction"
  342. ),
  343. settable: self
  344. ),
  345. Field(
  346. displayName: "Remaining Carbs Cap",
  347. type: .decimal(keypath: \.remainingCarbsCap),
  348. infoText: NSLocalizedString(
  349. "This is the amount of the maximum number of carbs we’ll assume will absorb over 4h if we don’t yet see carb absorption.",
  350. comment: "Remaining Carbs Cap"
  351. ),
  352. settable: self
  353. ),
  354. Field(
  355. displayName: "Noisy CGM Target Multiplier",
  356. type: .decimal(keypath: \.noisyCGMTargetMultiplier),
  357. infoText: NSLocalizedString(
  358. "Defaults to 1.3. Increase target by this amount when looping off raw/noisy CGM data",
  359. comment: "Noisy CGM Target Multiplier"
  360. ),
  361. settable: self
  362. )
  363. ]
  364. let xpmSettings = [
  365. Field(
  366. displayName: "Enable Floating Carbs",
  367. type: .boolean(keypath: \.floatingcarbs),
  368. infoText: NSLocalizedString(
  369. "Defaults to false. If true, then dose slightly more aggressively by using all entered carbs for calculating COBpredBGs. This avoids backing off too quickly as COB decays. Even with this option, oref0 still switches gradually from using COBpredBGs to UAMpredBGs proportionally to how many carbs are left as COB. Summary: use all entered carbs in the future for predBGs & don't decay them as COB, only once they are actual.",
  370. comment: "Floating Carbs"
  371. ),
  372. settable: self
  373. ),
  374. Field(
  375. displayName: "Enable AutoISF",
  376. type: .boolean(keypath: \.autoisf),
  377. infoText: NSLocalizedString(
  378. "Defaults to false. Adapt ISF when glucose is stuck at high levels, only works without COB.\n\nRead up on:\nhttps://github.com/ga-zelle/autoISF/tree/2.8.2",
  379. comment: "Enable AutoISF"
  380. ),
  381. settable: self
  382. ),
  383. Field(
  384. displayName: "Enable AutoISF with COB",
  385. type: .boolean(keypath: \.enableautoISFwithCOB),
  386. infoText: NSLocalizedString(
  387. "Enables autoISF not just for UAM, but also with COB\n\nRead up on:\nhttps://github.com/ga-zelle/autoISF/tree/2.8.2_dev_parabola",
  388. comment: "Enable autoISF with COB"
  389. ),
  390. settable: self
  391. ),
  392. Field(
  393. displayName: "AutoISF HourlyMaxChange",
  394. type: .decimal(keypath: \.autoISFhourlyChange),
  395. infoText: NSLocalizedString(
  396. "Defaults to false. Rate at which autoISF grows per hour assuming bg is twice target. When value = 1.0, ISF is reduced to 50% after 1 hour of BG at 2x target.",
  397. comment: "AutoISF HourlyMaxChange"
  398. ),
  399. settable: self
  400. ),
  401. Field(
  402. displayName: "AutoISF Max",
  403. type: .decimal(keypath: \.autoISFmax),
  404. infoText: NSLocalizedString(
  405. "Multiplier cap on how high the autoISF ratio can be and therefore how low it can adjust ISF.",
  406. comment: "AutoISF Max"
  407. ),
  408. settable: self
  409. ),
  410. Field(
  411. displayName: "AutoISF Min",
  412. type: .decimal(keypath: \.autoISFmin),
  413. infoText: NSLocalizedString(
  414. "This is a multiplier cap for autoISF to set a limit on how low the autoISF ratio can be, which in turn determines how high it can adjust ISF.",
  415. comment: "AutoISF Min"
  416. ),
  417. settable: self
  418. ),
  419. Field(
  420. displayName: "SMB Max RangeExtension",
  421. type: .decimal(keypath: \.smbMaxRangeExtension),
  422. infoText: NSLocalizedString(
  423. "Default value: 1. This is another key OpenAPS safety cap, and specifies by what factor you can exceed the regular 120 maxSMB/maxUAM minutes. Increase this experimental value slowly and with caution. Available only when autoISF is enabled.",
  424. comment: "SMB Max RangeExtension"
  425. ),
  426. settable: self
  427. ),
  428. Field(
  429. displayName: "SMB DeliveryRatio",
  430. type: .decimal(keypath: \.smbDeliveryRatio),
  431. infoText: NSLocalizedString(
  432. "Default value: 0.5 This is another key OpenAPS safety cap, and specifies what share of the total insulin required can be delivered as SMB. This is to prevent people from getting into dangerous territory by setting SMB requests from the caregivers phone at the same time. Increase this experimental value slowly and with caution.",
  433. comment: "SMB DeliveryRatio"
  434. ),
  435. settable: self
  436. ),
  437. Field(
  438. displayName: "SMB DeliveryRatio BG Range",
  439. type: .decimal(keypath: \.smbDeliveryRatioBGrange),
  440. infoText: NSLocalizedString(
  441. "Default value: 0, Sensible is bteween 40 and 120. The linearly increasing SMB delivery ratio is mapped to the glucose range [target_bg, target_bg+bg_range]. At target_bg the SMB ratio is smb_delivery_ratio_min, at target_bg+bg_range it is smb_delivery_ratio_max. With 0 the linearly increasing SMB ratio is disabled and the fix smb_delivery_ratio is used.",
  442. comment: "SMB DeliveryRatio BG Range"
  443. ),
  444. settable: self
  445. ),
  446. Field(
  447. displayName: "SMB DeliveryRatio BG Minimum",
  448. type: .decimal(keypath: \.smbDeliveryRatioMin),
  449. infoText: NSLocalizedString(
  450. "Default value: 0.5 This is the lower end of a linearly increasing SMB Delivery Ratio rather than the fix value above in SMB DeliveryRatio.",
  451. comment: "SMB DeliveryRatio Minimum"
  452. ),
  453. settable: self
  454. ),
  455. Field(
  456. displayName: "SMB DeliveryRatio BG Maximum",
  457. type: .decimal(keypath: \.smbDeliveryRatioMax),
  458. infoText: NSLocalizedString(
  459. "Default value: 0.5 This is the higher end of a linearly increasing SMB Delivery Ratio rather than the fix value above in SMB DeliveryRatio.",
  460. comment: "SMB DeliveryRatio Minimum"
  461. ),
  462. settable: self
  463. ),
  464. Field(
  465. displayName: "ISF weight while BG accelerates",
  466. type: .decimal(keypath: \.bgAccelISFweight),
  467. infoText: NSLocalizedString(
  468. "Default value: 0. This is the weight applied while glucose accelerates and which strengthens ISF. With 0 this contribution is effectively disabled.",
  469. comment: "ISF postprandial change duration"
  470. ),
  471. settable: self
  472. ),
  473. Field(
  474. displayName: "ISF weight while BG decelerates",
  475. type: .decimal(keypath: \.bgBrakeISFweight),
  476. infoText: NSLocalizedString(
  477. "Default value: 0. This is the weight applied while glucose decelerates and which weakens ISF. With 0 this contribution is effectively disabled.",
  478. comment: "ISF postprandial change duration"
  479. ),
  480. settable: self
  481. ),
  482. Field(
  483. displayName: "ISF weight for higher BG's",
  484. type: .decimal(keypath: \.higherISFrangeWeight),
  485. infoText: NSLocalizedString(
  486. "Default value: 0.0 This is the weight applied to the polygon which adapts ISF if glucose is above target. With 0.0 the effect is effectively disabled.",
  487. comment: "ISF high BG weight"
  488. ),
  489. settable: self
  490. ),
  491. Field(
  492. displayName: "ISF weight for lower BG's",
  493. type: .decimal(keypath: \.lowerISFrangeWeight),
  494. infoText: NSLocalizedString(
  495. "Default value: 0.0 This is the weight applied to the polygon which adapts ISF if glucose is below target. With 0.0 the effect is effectively disabled.",
  496. comment: "ISF low BG weight"
  497. ),
  498. settable: self
  499. ),
  500. Field(
  501. displayName: "ISF weight for higher BG deltas",
  502. type: .decimal(keypath: \.deltaISFrangeWeight),
  503. infoText: NSLocalizedString(
  504. "Default value: 0.0 This is the weight applied to the polygon which adapts ISF higher deltas. With 0.0 the effect is effectively disabled.",
  505. comment: "ISF higher delta BG weight"
  506. ),
  507. settable: self
  508. ),
  509. Field(
  510. displayName: "Enable always postprandial ISF adaption",
  511. type: .boolean(keypath: \.postMealISFalways),
  512. infoText: NSLocalizedString(
  513. "Enable the postprandial ISF adaptation all the time regardless of when the last meal was taken.",
  514. comment: "Enable postprandial ISF always"
  515. ),
  516. settable: self
  517. ),
  518. Field(
  519. displayName: "ISF weight for postprandial BG rise",
  520. type: .decimal(keypath: \.postMealISFweight),
  521. infoText: NSLocalizedString(
  522. "Default value: 0 This is the weight applied to the linear slope while glucose rises and which adapts ISF. With 0 this contribution is effectively disabled.",
  523. comment: "ISF postprandial weight"
  524. ),
  525. settable: self
  526. ),
  527. Field(
  528. displayName: "Duration ISF postprandial adaption",
  529. type: .decimal(keypath: \.postMealISFduration),
  530. infoText: NSLocalizedString(
  531. "Default value: 3 This is the duration in hours how long after a meal the effect will be active. Oref will delete carb timing after 10 hours latest no matter what you enter.",
  532. comment: "ISF postprandial change duration"
  533. ),
  534. settable: self
  535. )
  536. ]
  537. sections = [
  538. FieldSection(
  539. displayName: NSLocalizedString("OpenAPS main settings", comment: "OpenAPS main settings"), fields: mainFields
  540. ),
  541. FieldSection(
  542. displayName: NSLocalizedString("OpenAPS SMB settings", comment: "OpenAPS SMB settings"), fields: smbFields
  543. ),
  544. FieldSection(
  545. displayName: NSLocalizedString("OpenAPS targets settings", comment: "OpenAPS targets settings"),
  546. fields: targetSettings
  547. ),
  548. FieldSection(
  549. displayName: NSLocalizedString("OpenAPS other settings", comment: "OpenAPS other settings"),
  550. fields: otherSettings
  551. ),
  552. FieldSection(
  553. displayName: NSLocalizedString("XPM settings", comment: "Experimental stuff settings"),
  554. fields: xpmSettings
  555. )
  556. ]
  557. }
  558. func set<T>(_ keypath: WritableKeyPath<Preferences, T>, value: T) {
  559. preferences[keyPath: keypath] = value
  560. save()
  561. }
  562. func get<T>(_ keypath: WritableKeyPath<Preferences, T>) -> T {
  563. preferences[keyPath: keypath]
  564. }
  565. func save() {
  566. provider.savePreferences(preferences)
  567. }
  568. }
  569. }