From 2f85bbac0eae873e5330ae7d3e5e7b6c4c750058 Mon Sep 17 00:00:00 2001 From: Philoul Date: Tue, 13 Feb 2024 20:52:13 +0100 Subject: [PATCH 01/38] Initialize AutoISF Plugin from OpenAPSSMB --- .../aaps/activities/MyPreferenceFragment.kt | 3 + .../kotlin/app/aaps/di/PluginsListModule.kt | 7 + .../kotlin/app/aaps/core/keys/BooleanKey.kt | 7 + .../kotlin/app/aaps/core/keys/DoubleKey.kt | 13 + .../main/kotlin/app/aaps/core/keys/IntKey.kt | 2 + .../app/aaps/core/keys/UnitDoubleKey.kt | 2 + core/keys/src/main/res/values/keys.xml | 28 + .../openAPSAutoISF/DetermineBasalAutoISF.kt | 1139 +++++++++++++++++ .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 490 +++++++ plugins/aps/src/main/res/values/strings.xml | 61 + .../src/main/res/xml/pref_openapsautoisf.xml | 156 +++ 11 files changed, 1908 insertions(+) create mode 100644 plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt create mode 100644 plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt create mode 100644 plugins/aps/src/main/res/xml/pref_openapsautoisf.xml diff --git a/app/src/main/kotlin/app/aaps/activities/MyPreferenceFragment.kt b/app/src/main/kotlin/app/aaps/activities/MyPreferenceFragment.kt index ecde646bc99..7fe6b8052c7 100644 --- a/app/src/main/kotlin/app/aaps/activities/MyPreferenceFragment.kt +++ b/app/src/main/kotlin/app/aaps/activities/MyPreferenceFragment.kt @@ -40,6 +40,7 @@ import app.aaps.implementation.plugin.PluginStore import app.aaps.plugins.aps.autotune.AutotunePlugin import app.aaps.plugins.aps.loop.LoopPlugin import app.aaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin +import app.aaps.plugins.aps.openAPSAutoISF.OpenAPSAutoISFPlugin import app.aaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import app.aaps.plugins.automation.AutomationPlugin import app.aaps.plugins.configuration.maintenance.MaintenancePlugin @@ -110,6 +111,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang @Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin + @Inject lateinit var openAPSAutoISFPlugin: OpenAPSAutoISFPlugin @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var safetyPlugin: SafetyPlugin @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @@ -212,6 +214,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, config.APS) addPreferencesFromResourceIfEnabled(openAPSAMAPlugin, rootKey, config.APS) addPreferencesFromResourceIfEnabled(openAPSSMBPlugin, rootKey, config.APS) + addPreferencesFromResourceIfEnabled(openAPSAutoISFPlugin, rootKey, config.APS) addPreferencesFromResourceIfEnabled(sensitivityAAPSPlugin, rootKey) addPreferencesFromResourceIfEnabled(sensitivityWeightedAveragePlugin, rootKey) addPreferencesFromResourceIfEnabled(sensitivityOref1Plugin, rootKey) diff --git a/app/src/main/kotlin/app/aaps/di/PluginsListModule.kt b/app/src/main/kotlin/app/aaps/di/PluginsListModule.kt index bada5ab6e48..07da97d4426 100644 --- a/app/src/main/kotlin/app/aaps/di/PluginsListModule.kt +++ b/app/src/main/kotlin/app/aaps/di/PluginsListModule.kt @@ -4,6 +4,7 @@ import app.aaps.core.interfaces.plugin.PluginBase import app.aaps.plugins.aps.autotune.AutotunePlugin import app.aaps.plugins.aps.loop.LoopPlugin import app.aaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin +import app.aaps.plugins.aps.openAPSAutoISF.OpenAPSAutoISFPlugin import app.aaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import app.aaps.plugins.automation.AutomationPlugin import app.aaps.plugins.configuration.configBuilder.ConfigBuilderPlugin @@ -244,6 +245,12 @@ abstract class PluginsListModule { @IntKey(220) abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase + @Binds + @APS + @IntoMap + @IntKey(225) + abstract fun bindOpenAPSAutoISFPlugin(plugin: OpenAPSAutoISFPlugin): PluginBase + @Binds @AllConfigs @IntoMap diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt index 241c6b113b8..b00c4bb728f 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt @@ -44,4 +44,11 @@ enum class BooleanKey( ApsAmaAutosensAdjustTargets(R.string.key_openaps_ama_autosens_adjust_targets, true, defaultedBySM = true), ApsUseDynamicSensitivity(R.string.key_use_dynamic_sensitivity, false), MaintenanceEnableFabric(R.string.key_enable_fabric, true, defaultedBySM = true, hideParentScreenIfHidden = true), + ApsAutoIsfHighTtRaisesSens(R.string.key_high_temptarget_raises_sensitivity, false), + ApsAutoIsfLowTtLowersSens(R.string.key_low_temptarget_lowers_sensitivity, false), + ApsUseAutoIsf(R.string.key_enable_autoISF, false, defaultedBySM = true), + ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false), + ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false), + ApsAutoIsfSmbOnEvenTt(R.string.key_enableSMB_EvenOn_OddOff, false), // TempTarget + ApsAutoIsfSmbOnEvenPt(R.string.key_enableSMB_EvenOn_OddOff_always, false) // profile target } \ No newline at end of file diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt index b5cac7510d5..e3d3c0dca13 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt @@ -34,6 +34,19 @@ enum class DoubleKey( AbsorptionMaxTime(R.string.key_absorption_maxtime, 6.0, 4.0, 10.0), AutosensMin(R.string.key_openaps_autosens_min, 0.7, 0.1, 1.0, defaultedBySM = true, hideParentScreenIfHidden = true), AutosensMax(R.string.key_openaps_autosens_max, 1.2, 0.5, 3.0, defaultedBySM = true), + ApsAutoIsfMin(R.string.key_openapsama_autoISF_min, 1.0, 0.3, 1.0, defaultedBySM = true), + ApsAutoIsfMax(R.string.key_openapsama_autoISF_max, 1.0, 1.0, 5.0, defaultedBySM = true), + ApsAutoIsfBgAccelWeight(R.string.key_openapsama_bgAccel_ISF_weight, 0.0, 0.0, 1.0), + ApsAutoIsfBgBrakeWeight(R.string.key_openapsama_bgBrake_ISF_weight, 0.0, 0.0, 1.0), + ApsAutoIsfLowBgWeight(R.string.key_openapsama_lower_ISFrange_weight, 0.0, 0.0, 2.0), + ApsAutoIsfHighBgWeight(R.string.key_openapsama_higher_ISFrange_weight, 0.0, 0.0, 2.0), + ApsAutoIsfPpWeight(R.string.key_openapsama_pp_ISF_weight, 0.0, 0.0, 1.0), + ApsAutoIsfDeltaWeight(R.string.key_openapsama_delta_ISFrange_weight, 0.0, 0.0, 1.0), + ApsAutoIsfDuraWeight(R.string.key_openapsama_dura_ISF_weight, 0.0, 0.0, 3.0), + ApsAutoIsfSmbDeliveryRatio(R.string.key_openapsama_smb_delivery_ratio, 0.5, 0.5, 1.0), + ApsAutoIsfSmbDeliveryRatioMin(R.string.key_openapsama_smb_delivery_ratio_min, 0.5, 0.5, 1.0), + ApsAutoIsfSmbDeliveryRatioMax(R.string.key_openapsama_smb_delivery_ratio_max, 0.5, 0.5, 1.0), + ApsAutoIsfSmbMaxRangeExtension(R.string.key_openapsama_smb_max_range_extension, 1.0, 1.0, 5.0), EquilMaxBolus(R.string.key_equil_maxbolus, 10.0, 0.1, 25.0), } \ No newline at end of file diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt index 918b315be8f..08a981b5cbf 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt @@ -45,6 +45,8 @@ enum class IntKey( ApsMaxMinutesOfBasalToLimitSmb(R.string.key_openaps_smb_max_minutes, 30, 15, 120, defaultedBySM = true), ApsUamMaxMinutesOfBasalToLimitSmb(R.string.key_openaps_uam_smb_max_minutes, 30, 15, 120, defaultedBySM = true), ApsCarbsRequestThreshold(R.string.key_openaps_carbs_required_threshold, 1, 1, 10, defaultedBySM = true), + ApsAutoIsfPpIsfHours(R.string.key_openapsama_pp_ISF_hours, 3, 1, 10), + ApsAutoIsfIobThPercent(R.string.key_openapsama_iob_threshold_percent, 100, 10, 100), ApsDynIsfAdjustmentFactor(R.string.key_dynamic_isf_adjustment_factor, 100, 1, 300, dependency = R.string.key_use_dynamic_sensitivity), AutosensPeriod(R.string.key_openapsama_autosens_period, 24, 4, 24, calculatedDefaultValue = true), MaintenanceLogsAmount(R.string.key_maintenance_logs_amount, 2, 1, 10, defaultedBySM = true), diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt index 248a3691f6b..5315c0ef377 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt @@ -20,4 +20,6 @@ enum class UnitDoubleKey( OverviewLowMark(R.string.key_low_mark, 72.0, 25, 160, showInNsClientMode = false, hideParentScreenIfHidden = true), OverviewHighMark(R.string.key_high_mark, 180.0, 90, 250, showInNsClientMode = false), ApsLgsThreshold(R.string.key_dynamic_isf_lgs_threshold, 65.0, 65, 120, defaultedBySM = true, dependency = R.string.key_use_dynamic_sensitivity), + ApsAutoIsfHalfBasalExerciseTarget(R.string.key_half_basal_exercise_target, 160.0, 120, 200, defaultedBySM = true), + ApsAutoIsfSmbDeliveryRatioBgRange(R.string.key_openapsama_smb_delivery_ratio_bg_range, 0.0, 0, 100, defaultedBySM = true) } \ No newline at end of file diff --git a/core/keys/src/main/res/values/keys.xml b/core/keys/src/main/res/values/keys.xml index 24b5ab7a680..2bb09986cd3 100644 --- a/core/keys/src/main/res/values/keys.xml +++ b/core/keys/src/main/res/values/keys.xml @@ -130,4 +130,32 @@ pump_unreachable_threshold equil_maxbolus + + + half_basal_exercise_target + openapsama_enable_autoISF + openapsama_enable_autoISF + enable_dura_ISF_with_COB + autoISF_max + autoISF_min + dura_ISF_weight + lower_ISFrange_weight + higher_ISFrange_weight + delta_ISFrange_weight + pp_ISF_weight + pp_ISF_hours + enable_postprandial_ISF_always + bgAccel_ISF_weight + bgBrake_ISF_weight + openapsama_smb_delivery_ratio + openapsama_smb_delivery_ratio_min + openapsama_smb_delivery_ratio_max + openapsama_smb_delivery_ratio_bg_range + openapsama_smb_max_range_extension + Enable alternative activation of SMB + Enable alternative activation of SMB always + high_temptarget_raises_sensitivity + low_temptarget_lowers_sensitivity + iob_threshold_percent + \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt new file mode 100644 index 00000000000..84dc4243c6e --- /dev/null +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -0,0 +1,1139 @@ +package app.aaps.plugins.aps.openAPSAutoISF + +import app.aaps.core.interfaces.aps.APSResult +import app.aaps.core.interfaces.aps.AutosensResult +import app.aaps.core.interfaces.aps.CurrentTemp +import app.aaps.core.interfaces.aps.GlucoseStatus +import app.aaps.core.interfaces.aps.IobTotal +import app.aaps.core.interfaces.aps.MealData +import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.Predictions +import app.aaps.core.interfaces.aps.RT +import app.aaps.core.interfaces.profile.ProfileUtil +import java.text.DecimalFormat +import java.time.Instant +import java.time.ZoneId +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.ln +import kotlin.math.max +import kotlin.math.min +import kotlin.math.pow +import kotlin.math.roundToInt + +@Singleton +class DetermineBasalAutoISF @Inject constructor( + private val profileUtil: ProfileUtil +) { + + private val consoleError = mutableListOf() + private val consoleLog = mutableListOf() + + private fun Double.toFixed2(): String = DecimalFormat("0.00#").format(round(this, 2)) + + fun round_basal(value: Double): Double = value + + // Rounds value to 'digits' decimal places + // different for negative numbers fun round(value: Double, digits: Int): Double = BigDecimal(value).setScale(digits, RoundingMode.HALF_EVEN).toDouble() + fun round(value: Double, digits: Int): Double { + if (value.isNaN()) return Double.NaN + val scale = 10.0.pow(digits.toDouble()) + return Math.round(value * scale) / scale + } + + fun Double.withoutZeros(): String = DecimalFormat("0.##").format(this) + fun round(value: Double): Int = value.roundToInt() + + // we expect BG to rise or fall at the rate of BGI, + // adjusted by the rate at which BG would need to rise / + // fall to get eventualBG to target over 2 hours + fun calculate_expected_delta(targetBg: Double, eventualBg: Double, bgi: Double): Double { + // (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24 + val fiveMinBlocks = (2 * 60) / 5 + val targetDelta = targetBg - eventualBg + return /* expectedDelta */ round(bgi + (targetDelta / fiveMinBlocks), 1) + } + + fun convert_bg(value: Double): String = + profileUtil.fromMgdlToStringInUnits(value).replace("-0.0", "0.0") + //DecimalFormat("0.#").format(profileUtil.fromMgdlToUnits(value)) + //if (profile.out_units === "mmol/L") round(value / 18, 1).toFixed(1); + //else Math.round(value); + + fun enable_smb(profile: OapsProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { + // disable SMB when a high temptarget is set + if (!microBolusAllowed) { + consoleError.add("SMB disabled (!microBolusAllowed)") + return false + } else if (!profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) { + consoleError.add("SMB disabled due to high temptarget of $target_bg") + return false + } + + // enable SMB/UAM if always-on (unless previously disabled for high temptarget) + if (profile.enableSMB_always) { + consoleError.add("SMB enabled due to enableSMB_always") + return true + } + + // enable SMB/UAM (if enabled in preferences) while we have COB + if (profile.enableSMB_with_COB && meal_data.mealCOB != 0.0) { + consoleError.add("SMB enabled for COB of ${meal_data.mealCOB}") + return true + } + + // enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry + // (6 hours is defined in carbWindow in lib/meal/total.js) + if (profile.enableSMB_after_carbs && meal_data.carbs != 0.0) { + consoleError.add("SMB enabled for 6h after carb entry") + return true + } + + // enable SMB/UAM (if enabled in preferences) if a low temptarget is set + if (profile.enableSMB_with_temptarget && (profile.temptargetSet && target_bg < 100)) { + consoleError.add("SMB enabled for temptarget of ${convert_bg(target_bg)}") + return true + } + + consoleError.add("SMB disabled (no enableSMB preferences active or no condition satisfied)") + return false + } + + fun reason(rT: RT, msg: String) { + if (rT.reason.toString().isNotEmpty()) rT.reason.append(". ") + rT.reason.append(msg) + consoleError.add(msg) + } + + private fun getMaxSafeBasal(profile: OapsProfile): Double = + min(profile.max_basal, min(profile.max_daily_safety_multiplier * profile.max_daily_basal, profile.current_basal_safety_multiplier * profile.current_basal)) + + fun setTempBasal(_rate: Double, duration: Int, profile: OapsProfile, rT: RT, currenttemp: CurrentTemp): RT { + //var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); + + val maxSafeBasal = getMaxSafeBasal(profile) + var rate = _rate + if (rate < 0) rate = 0.0 + else if (rate > maxSafeBasal) rate = maxSafeBasal + + val suggestedRate = round_basal(rate) + if (currenttemp.duration > (duration - 10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8 && duration > 0) { + rT.reason.append(" ${currenttemp.duration}m left and ${currenttemp.rate.withoutZeros()} ~ req ${suggestedRate.withoutZeros()}U/hr: no temp required") + return rT + } + + if (suggestedRate == profile.current_basal) { + if (profile.skip_neutral_temps) { + if (currenttemp.duration > 0) { + reason(rT, "Suggested rate is same as profile rate, a temp basal is active, canceling current temp") + rT.duration = 0 + rT.rate = 0.0 + return rT + } else { + reason(rT, "Suggested rate is same as profile rate, no temp basal is active, doing nothing") + return rT + } + } else { + reason(rT, "Setting neutral temp basal of ${profile.current_basal}U/hr") + rT.duration = duration + rT.rate = suggestedRate + return rT + } + } else { + rT.duration = duration + rT.rate = suggestedRate + return rT + } + } + + fun determine_basal( + glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, + microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean + ): RT { + consoleError.clear() + consoleLog.clear() + var rT = RT( + algorithm = APSResult.Algorithm.SMB, + runningDynamicIsf = dynIsfMode, + timestamp = currentTime, + consoleLog = consoleLog, + consoleError = consoleError + ) + + // TODO eliminate + val deliverAt = currentTime + + // TODO eliminate + val profile_current_basal = round_basal(profile.current_basal) + var basal = profile_current_basal + + // TODO eliminate + val systemTime = currentTime + + // TODO eliminate + val bgTime = glucose_status.date + val minAgo = round((systemTime - bgTime) / 60.0 / 1000.0, 1) + // TODO eliminate + val bg = glucose_status.glucose + // TODO eliminate + val noise = glucose_status.noise + // 38 is an xDrip error state that usually indicates sensor failure + // all other BG values between 11 and 37 mg/dL reflect non-error-code BG values, so we should zero temp for those + if (bg <= 10 || bg == 38.0 || noise >= 3) { //Dexcom is in ??? mode or calibrating, or xDrip reports high noise + rT.reason.append("CGM is calibrating, in ??? state, or noise is high") + } + if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future + rT.reason.append("If current system time $systemTime is correct, then BG data is too old. The last BG data was read ${minAgo}m ago at $bgTime") + // if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps + } else if (bg > 60 && flatBGsDetected) { + rT.reason.append("Error: CGM data is unchanged for the past ~45m") + } + if (bg <= 10 || bg == 38.0 || noise >= 3 || minAgo > 12 || minAgo < -5 || (bg > 60 && flatBGsDetected)) { + if (currenttemp.rate > basal) { // high temp is running + rT.reason.append(". Replacing high temp basal of ${currenttemp.rate} with neutral temp of $basal") + rT.deliverAt = deliverAt + rT.duration = 30 + rT.rate = basal + return rT + } else if (currenttemp.rate == 0.0 && currenttemp.duration > 30) { //shorten long zero temps to 30m + rT.reason.append(". Shortening " + currenttemp.duration + "m long zero temp to 30m. ") + rT.deliverAt = deliverAt + rT.duration = 30 + rT.rate = 0.0 + return rT + } else { //do nothing. + rT.reason.append(". Temp ${currenttemp.rate} <= current basal ${round(basal, 2)}U/hr; doing nothing. ") + return rT + } + } + + // TODO eliminate + val max_iob = profile.max_iob // maximum amount of non-bolus IOB OpenAPS will ever deliver + + // if min and max are set, then set target to their average + var target_bg = (profile.min_bg + profile.max_bg) / 2 + var min_bg = profile.min_bg + var max_bg = profile.max_bg + + var sensitivityRatio: Double + val high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity + val normalTarget = 100 // evaluate high/low temptarget against 100, not scheduled target (which might change) + // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%), 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) + val halfBasalTarget = profile.half_basal_exercise_target + + if (dynIsfMode) { + consoleError.add("---------------------------------------------------------") + consoleError.add(" Dynamic ISF version 2.0 ") + consoleError.add("---------------------------------------------------------") + } + + if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget + ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + val c = (halfBasalTarget - normalTarget).toDouble() + sensitivityRatio = c / (c + target_bg - normalTarget) + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = min(sensitivityRatio, profile.autosens_max) + sensitivityRatio = round(sensitivityRatio, 2) + consoleLog.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") + } else { + sensitivityRatio = autosens_data.ratio + consoleLog.add("Autosens ratio: $sensitivityRatio; ") + } + basal = profile.current_basal * sensitivityRatio + basal = round_basal(basal) + if (basal != profile_current_basal) + consoleLog.add("Adjusting basal from $profile_current_basal to $basal; ") + else + consoleLog.add("Basal unchanged: $basal; ") + + // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120 + if (profile.temptargetSet) { + //console.log("Temp Target set, not adjusting with autosens; "); + } else { + if (profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1) { + // with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range + min_bg = round((min_bg - 60) / autosens_data.ratio, 0) + 60 + max_bg = round((max_bg - 60) / autosens_data.ratio, 0) + 60 + var new_target_bg = round((target_bg - 60) / autosens_data.ratio, 0) + 60 + // don't allow target_bg below 80 + new_target_bg = max(80.0, new_target_bg) + if (target_bg == new_target_bg) + consoleLog.add("target_bg unchanged: $new_target_bg; ") + else + consoleLog.add("target_bg from $target_bg to $new_target_bg; ") + + target_bg = new_target_bg + } + } + + val iobArray = iob_data_array + val iob_data = iobArray[0] + + val tick: String + + tick = if (glucose_status.delta > -0.5) { + "+" + round(glucose_status.delta) + } else { + round(glucose_status.delta).toString() + } + val minDelta = min(glucose_status.delta, glucose_status.shortAvgDelta) + val minAvgDelta = min(glucose_status.shortAvgDelta, glucose_status.longAvgDelta) + val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) + + val sens = + if (dynIsfMode) profile.variable_sens + else { + val profile_sens = round(profile.sens, 1) + val adjusted_sens = round(profile.sens / sensitivityRatio, 1) + if (adjusted_sens != profile_sens) { + consoleLog.add("ISF from $profile_sens to $adjusted_sens") + } else { + consoleLog.add("ISF unchanged: $adjusted_sens") + } + adjusted_sens + //console.log(" (autosens ratio "+sensitivityRatio+")"); + } + consoleError.add("CR:${profile.carb_ratio}") + + //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone + val bgi = round((-iob_data.activity * sens * 5), 2) + // project deviations for 30 minutes + var deviation = round(30 / 5 * (minDelta - bgi)) + // don't overreact to a big negative delta: use minAvgDelta if deviation is negative + if (deviation < 0) { + deviation = round((30 / 5) * (minAvgDelta - bgi)) + // and if deviation is still negative, use long_avgdelta + if (deviation < 0) { + deviation = round((30 / 5) * (glucose_status.longAvgDelta - bgi)) + } + } + + // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity + val naive_eventualBG = + if (dynIsfMode) + round(bg - (iob_data.iob * sens), 0) + else { + if (iob_data.iob > 0) round(bg - (iob_data.iob * sens), 0) + else // if IOB is negative, be more conservative and use the lower of sens, profile.sens + round(bg - (iob_data.iob * min(sens, profile.sens)), 0) + } + // and adjust it for the deviation above + var eventualBG = naive_eventualBG + deviation + + // raise target for noisy / raw CGM data + if (bg > max_bg && profile.adv_target_adjustments && !profile.temptargetSet) { + // with target=100, as BG rises from 100 to 160, adjustedTarget drops from 100 to 80 + val adjustedMinBG = round(max(80.0, min_bg - (bg - min_bg) / 3.0), 0) + val adjustedTargetBG = round(max(80.0, target_bg - (bg - target_bg) / 3.0), 0) + val adjustedMaxBG = round(max(80.0, max_bg - (bg - max_bg) / 3.0), 0) + // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it + //console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG); + if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) { + consoleLog.add("Adjusting targets for high BG: min_bg from $min_bg to $adjustedMinBG; ") + min_bg = adjustedMinBG + } else { + consoleLog.add("min_bg unchanged: $min_bg; ") + } + // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it + if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) { + consoleLog.add("target_bg from $target_bg to $adjustedTargetBG; ") + target_bg = adjustedTargetBG + } else { + consoleLog.add("target_bg unchanged: $target_bg; ") + } + // if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it + if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) { + consoleError.add("max_bg from $max_bg to $adjustedMaxBG") + max_bg = adjustedMaxBG + } else { + consoleError.add("max_bg unchanged: $max_bg") + } + } + + val expectedDelta = calculate_expected_delta(target_bg, eventualBG, bgi) + + // min_bg of 90 -> threshold of 65, 100 -> 70 110 -> 75, and 130 -> 85 + var threshold = min_bg - 0.5 * (min_bg - 40) + if (profile.lgsThreshold != null) { + val lgsThreshold = profile.lgsThreshold ?: error("lgsThreshold missing") + if (lgsThreshold > threshold) { + consoleError.add("Threshold set from ${convert_bg(threshold)} to ${convert_bg(lgsThreshold.toDouble())}; ") + threshold = lgsThreshold.toDouble() + } + } + + //console.error(reservoir_data); + + rT = RT( + algorithm = APSResult.Algorithm.SMB, + runningDynamicIsf = dynIsfMode, + timestamp = currentTime, + bg = bg, + tick = tick, + eventualBG = eventualBG, + targetBG = target_bg, + insulinReq = 0.0, + deliverAt = deliverAt, // The time at which the microbolus should be delivered + sensitivityRatio = sensitivityRatio, // autosens ratio (fraction of normal basal) + consoleLog = consoleLog, + consoleError = consoleError, + variable_sens = profile.variable_sens + ) + + // generate predicted future BGs based on IOB, COB, and current absorption rate + + var COBpredBGs = mutableListOf() + var aCOBpredBGs = mutableListOf() + var IOBpredBGs = mutableListOf() + var UAMpredBGs = mutableListOf() + var ZTpredBGs = mutableListOf() + COBpredBGs.add(bg) + aCOBpredBGs.add(bg) + IOBpredBGs.add(bg) + ZTpredBGs.add(bg) + UAMpredBGs.add(bg) + + var enableSMB = enable_smb(profile, microBolusAllowed, meal_data, target_bg) + + // enable UAM (if enabled in preferences) + val enableUAM = profile.enableUAM + + //console.error(meal_data); + // carb impact and duration are 0 unless changed below + var ci: Double + val cid: Double + // calculate current carb absorption rate, and how long to absorb all carbs + // CI = current carb impact on BG in mg/dL/5m + ci = round((minDelta - bgi), 1) + val uci = round((minDelta - bgi), 1) + // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g) + + // TODO: remove commented-out code for old behavior + //if (profile.temptargetSet) { + // if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR + //var csf = profile.sens / profile.carb_ratio; + //} else { + // otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments + // so that autotuned CR is still in effect even when basals and ISF are being adjusted by autosens + //var csf = sens / profile.carb_ratio; + //} + // use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments so that + // autotuned CR is still in effect even when basals and ISF are being adjusted by TT or autosens + // this avoids overdosing insulin for large meals when low temp targets are active + val csf = sens / profile.carb_ratio + consoleError.add("profile.sens: ${profile.sens}, sens: $sens, CSF: $csf") + + val maxCarbAbsorptionRate = 30 // g/h; maximum rate to assume carbs will absorb if no CI observed + // limit Carb Impact to maxCarbAbsorptionRate * csf in mg/dL per 5m + val maxCI = round(maxCarbAbsorptionRate * csf * 5 / 60, 1) + if (ci > maxCI) { + consoleError.add("Limiting carb impact from $ci to $maxCI mg/dL/5m ( $maxCarbAbsorptionRate g/h )") + ci = maxCI + } + var remainingCATimeMin = 3.0 // h; duration of expected not-yet-observed carb absorption + // adjust remainingCATime (instead of CR) for autosens if sensitivityRatio defined + remainingCATimeMin = remainingCATimeMin / sensitivityRatio + // 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h + // when actual absorption ramps up it will take over from remainingCATime + val assumedCarbAbsorptionRate = 20 // g/h; maximum rate to assume carbs will absorb if no CI observed + var remainingCATime = remainingCATimeMin + if (meal_data.carbs != 0.0) { + // if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it + // so <= 90g is assumed to take 3h, and 120g=4h + remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB / assumedCarbAbsorptionRate) + val lastCarbAge = round((systemTime - meal_data.lastCarbTime) / 60000.0) + //console.error(meal_data.lastCarbTime, lastCarbAge); + + val fractionCOBAbsorbed = (meal_data.carbs - meal_data.mealCOB) / meal_data.carbs + remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge / 60 + remainingCATime = round(remainingCATime, 1) + //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) + consoleError.add("Last carbs " + lastCarbAge + "minutes ago; remainingCATime:" + remainingCATime + "hours;" + round(fractionCOBAbsorbed * 100) + "% carbs absorbed") + } + + // calculate the number of carbs absorbed over remainingCATime hours at current CI + // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL) + val totalCI = Math.max(0.0, ci / 5 * 60 * remainingCATime / 2) + // totalCI (mg/dL) / CSF (mg/dL/g) = total carbs absorbed (g) + val totalCA = totalCI / csf + val remainingCarbsCap: Int // default to 90 + remainingCarbsCap = min(90, profile.remainingCarbsCap) + var remainingCarbs = max(0.0, meal_data.mealCOB - totalCA) + remainingCarbs = Math.min(remainingCarbsCap.toDouble(), remainingCarbs) + // assume remainingCarbs will absorb in a /\ shaped bilinear curve + // peaking at remainingCATime / 2 and ending at remainingCATime hours + // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to remainingCATime/2 + // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h) + val remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime / 2) + //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime); + + // calculate peak deviation in last hour, and slope from that to current deviation + val slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation, 2) + // calculate lowest deviation in last hour, and slope from that to current deviation + val slopeFromMinDeviation = round(meal_data.slopeFromMinDeviation, 2) + // assume deviations will drop back down at least at 1/3 the rate they ramped up + val slopeFromDeviations = Math.min(slopeFromMaxDeviation, -slopeFromMinDeviation / 3) + //console.error(slopeFromMaxDeviation); + + val aci = 10 + //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) + // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m) + // limit cid to remainingCATime hours: the reset goes to remainingCI + if (ci == 0.0) { + // avoid divide by zero + cid = 0.0 + } else { + cid = min(remainingCATime * 60 / 5 / 2, Math.max(0.0, meal_data.mealCOB * csf / ci)) + } + val acid = max(0.0, meal_data.mealCOB * csf / aci) + // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) + consoleError.add("Carb Impact: ${ci} mg/dL per 5m; CI Duration: ${round(cid * 5 / 60 * 2, 1)} hours; remaining CI (~2h peak): ${round(remainingCIpeak, 1)} mg/dL per 5m") + //console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); + var minIOBPredBG = 999.0 + var minCOBPredBG = 999.0 + var minUAMPredBG = 999.0 + var minGuardBG: Double + var minCOBGuardBG = 999.0 + var minUAMGuardBG = 999.0 + var minIOBGuardBG = 999.0 + var minZTGuardBG = 999.0 + var minPredBG: Double + var avgPredBG: Double + var IOBpredBG: Double = eventualBG + var maxIOBPredBG = bg + var maxCOBPredBG = bg + //var maxUAMPredBG = bg + //var maxPredBG = bg; + //var eventualPredBG = bg + val lastIOBpredBG: Double + var lastCOBpredBG: Double? = null + var lastUAMpredBG: Double? = null + //var lastZTpredBG: Int + var UAMduration = 0.0 + var remainingCItotal = 0.0 + val remainingCIs = mutableListOf() + val predCIs = mutableListOf() + var UAMpredBG: Double? = null + var COBpredBG: Double? = null + var aCOBpredBG: Double? + iobArray.forEach { iobTick -> + //console.error(iobTick); + val predBGI: Double = round((-iobTick.activity * sens * 5), 2) + val IOBpredBGI: Double = + if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(IOBpredBGs[IOBpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + else predBGI + iobTick.iobWithZeroTemp ?: error("iobTick.iobWithZeroTemp missing") + val predZTBGI = + if (dynIsfMode) round((-iobTick.iobWithZeroTemp!!.activity * (1800 / (profile.TDD * (ln((max(ZTpredBGs[ZTpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + else round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) + val predUAMBGI = + if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(UAMpredBGs[UAMpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + else predBGI + // for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero + // over 60 minutes (data points every 5m) + val predDev: Double = ci * (1 - min(1.0, IOBpredBGs.size / (60.0 / 5.0))) + IOBpredBG = IOBpredBGs[IOBpredBGs.size - 1] + IOBpredBGI + predDev + // calculate predBGs with long zero temp without deviations + val ZTpredBG = ZTpredBGs[ZTpredBGs.size - 1] + predZTBGI + // for COBpredBGs, predicted carb impact drops linearly from current carb impact down to zero + // eventually accounting for all carbs (if they can be absorbed over DIA) + val predCI: Double = max(0.0, max(0.0, ci) * (1 - COBpredBGs.size / max(cid * 2, 1.0))) + val predACI = max(0.0, max(0, aci) * (1 - COBpredBGs.size / max(acid * 2, 1.0))) + // if any carbs aren't absorbed after remainingCATime hours, assume they'll absorb in a /\ shaped + // bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m) + // and ending at remainingCATime h (remainingCATime*12 * 5m intervals) + val intervals = Math.min(COBpredBGs.size.toDouble(), ((remainingCATime * 12) - COBpredBGs.size)) + val remainingCI = Math.max(0.0, intervals / (remainingCATime / 2 * 12) * remainingCIpeak) + remainingCItotal += predCI + remainingCI + remainingCIs.add(round(remainingCI)) + predCIs.add(round(predCI)) + //console.log(round(predCI,1)+"+"+round(remainingCI,1)+" "); + COBpredBG = COBpredBGs[COBpredBGs.size - 1] + predBGI + min(0.0, predDev) + predCI + remainingCI + aCOBpredBG = aCOBpredBGs[aCOBpredBGs.size - 1] + predBGI + min(0.0, predDev) + predACI + // for UAMpredBGs, predicted carb impact drops at slopeFromDeviations + // calculate predicted CI from UAM based on slopeFromDeviations + val predUCIslope = max(0.0, uci + (UAMpredBGs.size * slopeFromDeviations)) + // if slopeFromDeviations is too flat, predicted deviation impact drops linearly from + // current deviation down to zero over 3h (data points every 5m) + val predUCImax = max(0.0, uci * (1 - UAMpredBGs.size / max(3.0 * 60 / 5, 1.0))) + //console.error(predUCIslope, predUCImax); + // predicted CI from UAM is the lesser of CI based on deviationSlope or DIA + val predUCI = min(predUCIslope, predUCImax) + if (predUCI > 0) { + //console.error(UAMpredBGs.length,slopeFromDeviations, predUCI); + UAMduration = round((UAMpredBGs.size + 1) * 5 / 60.0, 1) + } + UAMpredBG = UAMpredBGs[UAMpredBGs.size - 1] + predUAMBGI + min(0.0, predDev) + predUCI + //console.error(predBGI, predCI, predUCI); + // truncate all BG predictions at 4 hours + if (IOBpredBGs.size < 48) IOBpredBGs.add(IOBpredBG) + if (COBpredBGs.size < 48) COBpredBGs.add(COBpredBG!!) + if (aCOBpredBGs.size < 48) aCOBpredBGs.add(aCOBpredBG!!) + if (UAMpredBGs.size < 48) UAMpredBGs.add(UAMpredBG!!) + if (ZTpredBGs.size < 48) ZTpredBGs.add(ZTpredBG) + // calculate minGuardBGs without a wait from COB, UAM, IOB predBGs + if (COBpredBG!! < minCOBGuardBG) minCOBGuardBG = round(COBpredBG!!).toDouble() + if (UAMpredBG!! < minUAMGuardBG) minUAMGuardBG = round(UAMpredBG!!).toDouble() + if (IOBpredBG < minIOBGuardBG) minIOBGuardBG = IOBpredBG + if (ZTpredBG < minZTGuardBG) minZTGuardBG = round(ZTpredBG, 0) + + // set minPredBGs starting when currently-dosed insulin activity will peak + // look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins + // add 30m to allow for insulin delivery (SMBs or temps) + val insulinPeakTime = 90 + val insulinPeak5m = (insulinPeakTime / 60.0) * 12.0 + //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve); + + // wait 90m before setting minIOBPredBG + if (IOBpredBGs.size > insulinPeak5m && (IOBpredBG < minIOBPredBG)) minIOBPredBG = round(IOBpredBG, 0) + if (IOBpredBG > maxIOBPredBG) maxIOBPredBG = IOBpredBG + // wait 85-105m before setting COB and 60m for UAM minPredBGs + if ((cid != 0.0 || remainingCIpeak > 0) && COBpredBGs.size > insulinPeak5m && (COBpredBG!! < minCOBPredBG)) minCOBPredBG = round(COBpredBG!!, 0) + if ((cid != 0.0 || remainingCIpeak > 0) && COBpredBG!! > maxIOBPredBG) maxCOBPredBG = COBpredBG!! + if (enableUAM && UAMpredBGs.size > 12 && (UAMpredBG!! < minUAMPredBG)) minUAMPredBG = round(UAMpredBG!!, 0) + //if (enableUAM && UAMpredBG!! > maxIOBPredBG) maxUAMPredBG = UAMpredBG!! + } + // set eventualBG to include effect of carbs + //console.error("PredBGs:",JSON.stringify(predBGs)); + if (meal_data.mealCOB > 0) { + consoleError.add("predCIs (mg/dL/5m):" + predCIs.joinToString(separator = " ")) + consoleError.add("remainingCIs: " + remainingCIs.joinToString(separator = " ")) + } + rT.predBGs = Predictions() + IOBpredBGs = IOBpredBGs.map { round(min(401.0, max(39.0, it)), 0) }.toMutableList() + for (i in IOBpredBGs.size - 1 downTo 13) { + if (IOBpredBGs[i - 1] != IOBpredBGs[i]) break + else IOBpredBGs.removeLast() + } + rT.predBGs?.IOB = IOBpredBGs.map { it.toInt() } + lastIOBpredBG = round(IOBpredBGs[IOBpredBGs.size - 1]).toDouble() + ZTpredBGs = ZTpredBGs.map { round(min(401.0, max(39.0, it)), 0) }.toMutableList() + for (i in ZTpredBGs.size - 1 downTo 7) { + // stop displaying ZTpredBGs once they're rising and above target + if (ZTpredBGs[i - 1] >= ZTpredBGs[i] || ZTpredBGs[i] <= target_bg) break + else ZTpredBGs.removeLast() + } + rT.predBGs?.ZT = ZTpredBGs.map { it.toInt() } + if (meal_data.mealCOB > 0) { + aCOBpredBGs = aCOBpredBGs.map { round(min(401.0, max(39.0, it)), 0) }.toMutableList() + for (i in aCOBpredBGs.size - 1 downTo 13) { + if (aCOBpredBGs[i - 1] != aCOBpredBGs[i]) break + else aCOBpredBGs.removeLast() + } + } + if (meal_data.mealCOB > 0 && (ci > 0 || remainingCIpeak > 0)) { + COBpredBGs = COBpredBGs.map { round(min(401.0, max(39.0, it)), 0) }.toMutableList() + for (i in COBpredBGs.size - 1 downTo 13) { + if (COBpredBGs[i - 1] != COBpredBGs[i]) break + else COBpredBGs.removeLast() + } + rT.predBGs?.COB = COBpredBGs.map { it.toInt() } + lastCOBpredBG = COBpredBGs[COBpredBGs.size - 1] + eventualBG = max(eventualBG, round(COBpredBGs[COBpredBGs.size - 1], 0)) + } + if (ci > 0 || remainingCIpeak > 0) { + if (enableUAM) { + UAMpredBGs = UAMpredBGs.map { round(min(401.0, max(39.0, it)), 0) }.toMutableList() + for (i in UAMpredBGs.size - 1 downTo 13) { + if (UAMpredBGs[i - 1] != UAMpredBGs[i]) break + else UAMpredBGs.removeLast() + } + rT.predBGs?.UAM = UAMpredBGs.map { it.toInt() } + lastUAMpredBG = UAMpredBGs[UAMpredBGs.size - 1] + eventualBG = max(eventualBG, round(UAMpredBGs[UAMpredBGs.size - 1], 0)) + } + + // set eventualBG based on COB or UAM predBGs + rT.eventualBG = eventualBG + } + + consoleError.add("UAM Impact: $uci mg/dL per 5m; UAM Duration: $UAMduration hours") + consoleLog.add("EventualBG is $eventualBG ;") + + minIOBPredBG = max(39.0, minIOBPredBG) + minCOBPredBG = max(39.0, minCOBPredBG) + minUAMPredBG = max(39.0, minUAMPredBG) + minPredBG = round(minIOBPredBG, 0) + + val fSensBG = min(minPredBG, bg) + + var future_sens: Double + if (bg > target_bg && glucose_status.delta < 3 && glucose_status.delta > -3 && glucose_status.shortAvgDelta > -3 && glucose_status.shortAvgDelta < 3 && eventualBG > target_bg && eventualBG + < bg + ) { + future_sens = (1800 / (ln((((fSensBG * 0.5) + (bg * 0.5)) / profile.insulinDivisor) + 1) * profile.TDD)) + future_sens = round(future_sens, 1) + consoleLog.add("Future state sensitivity is $future_sens based on eventual and current bg due to flat glucose level above target") + rT.reason.append("Dosing sensitivity: $future_sens using eventual BG;") + } else if (glucose_status.delta > 0 && eventualBG > target_bg || eventualBG > bg) { + future_sens = (1800 / (ln((bg / profile.insulinDivisor) + 1) * profile.TDD)) + future_sens = round(future_sens, 1) + consoleLog.add("Future state sensitivity is $future_sens using current bg due to small delta or variation") + rT.reason.append("Dosing sensitivity: $future_sens using current BG;") + } else { + future_sens = (1800 / (ln((fSensBG / profile.insulinDivisor) + 1) * profile.TDD)) + future_sens = round(future_sens, 1) + consoleLog.add("Future state sensitivity is $future_sens based on eventual bg due to -ve delta") + rT.reason.append("Dosing sensitivity: $future_sens using eventual BG;") + } + + val fractionCarbsLeft = meal_data.mealCOB / meal_data.carbs + // if we have COB and UAM is enabled, average both + if (minUAMPredBG < 999 && minCOBPredBG < 999) { + // weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB + avgPredBG = round((1 - fractionCarbsLeft) * UAMpredBG!! + fractionCarbsLeft * COBpredBG!!, 0) + // if UAM is disabled, average IOB and COB + } else if (minCOBPredBG < 999) { + avgPredBG = round((IOBpredBG + COBpredBG!!) / 2.0, 0) + // if we have UAM but no COB, average IOB and UAM + } else if (minUAMPredBG < 999) { + avgPredBG = round((IOBpredBG + UAMpredBG!!) / 2.0, 0) + } else { + avgPredBG = round(IOBpredBG, 0) + } + // if avgPredBG is below minZTGuardBG, bring it up to that level + if (minZTGuardBG > avgPredBG) { + avgPredBG = minZTGuardBG + } + + // if we have both minCOBGuardBG and minUAMGuardBG, blend according to fractionCarbsLeft + if ((cid > 0.0 || remainingCIpeak > 0)) { + if (enableUAM) { + minGuardBG = fractionCarbsLeft * minCOBGuardBG + (1 - fractionCarbsLeft) * minUAMGuardBG + } else { + minGuardBG = minCOBGuardBG + } + } else if (enableUAM) { + minGuardBG = minUAMGuardBG + } else { + minGuardBG = minIOBGuardBG + } + minGuardBG = round(minGuardBG, 0) + //console.error(minCOBGuardBG, minUAMGuardBG, minIOBGuardBG, minGuardBG); + + var minZTUAMPredBG = minUAMPredBG + // if minZTGuardBG is below threshold, bring down any super-high minUAMPredBG by averaging + // this helps prevent UAM from giving too much insulin in case absorption falls off suddenly + if (minZTGuardBG < threshold) { + minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2.0 + // if minZTGuardBG is between threshold and target, blend in the averaging + } else if (minZTGuardBG < target_bg) { + // target 100, threshold 70, minZTGuardBG 85 gives 50%: (85-70) / (100-70) + val blendPct = (minZTGuardBG - threshold) / (target_bg - threshold) + val blendedMinZTGuardBG = minUAMPredBG * blendPct + minZTGuardBG * (1 - blendPct) + minZTUAMPredBG = (minUAMPredBG + blendedMinZTGuardBG) / 2.0 + //minZTUAMPredBG = minUAMPredBG - target_bg + minZTGuardBG; + // if minUAMPredBG is below minZTGuardBG, bring minUAMPredBG up by averaging + // this allows more insulin if lastUAMPredBG is below target, but minZTGuardBG is still high + } else if (minZTGuardBG > minUAMPredBG) { + minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2.0 + } + minZTUAMPredBG = round(minZTUAMPredBG, 0) + //console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG); + // if any carbs have been entered recently + if (meal_data.carbs != 0.0) { + + // if UAM is disabled, use max of minIOBPredBG, minCOBPredBG + if (!enableUAM && minCOBPredBG < 999) { + minPredBG = round(max(minIOBPredBG, minCOBPredBG), 0) + // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher + } else if (minCOBPredBG < 999) { + // calculate blendedMinPredBG based on how many carbs remain as COB + val blendedMinPredBG = fractionCarbsLeft * minCOBPredBG + (1 - fractionCarbsLeft) * minZTUAMPredBG + // if blendedMinPredBG > minCOBPredBG, use that instead + minPredBG = round(max(minIOBPredBG, max(minCOBPredBG, blendedMinPredBG)), 0) + // if carbs have been entered, but have expired, use minUAMPredBG + } else if (enableUAM) { + minPredBG = minZTUAMPredBG + } else { + minPredBG = minGuardBG + } + // in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG + } else if (enableUAM) { + minPredBG = round(max(minIOBPredBG, minZTUAMPredBG), 0) + } + // make sure minPredBG isn't higher than avgPredBG + minPredBG = min(minPredBG, avgPredBG) + + consoleLog.add("minPredBG: $minPredBG minIOBPredBG: $minIOBPredBG minZTGuardBG: $minZTGuardBG") + if (minCOBPredBG < 999) { + consoleLog.add(" minCOBPredBG: $minCOBPredBG") + } + if (minUAMPredBG < 999) { + consoleLog.add(" minUAMPredBG: $minUAMPredBG") + } + consoleError.add(" avgPredBG: $avgPredBG COB: ${meal_data.mealCOB} / ${meal_data.carbs}") + // But if the COB line falls off a cliff, don't trust UAM too much: + // use maxCOBPredBG if it's been set and lower than minPredBG + if (maxCOBPredBG > bg) { + minPredBG = min(minPredBG, maxCOBPredBG) + } + + rT.COB = meal_data.mealCOB + rT.IOB = iob_data.iob + rT.reason.append( + "COB: ${round(meal_data.mealCOB, 1).withoutZeros()}, Dev: ${convert_bg(deviation.toDouble())}, BGI: ${convert_bg(bgi)}, ISF: ${convert_bg(sens)}, CR: ${ + round(profile.carb_ratio, 2) + .withoutZeros() + }, Target: ${convert_bg(target_bg)}, minPredBG ${convert_bg(minPredBG)}, minGuardBG ${convert_bg(minGuardBG)}, IOBpredBG ${convert_bg(lastIOBpredBG)}" + ) + if (lastCOBpredBG != null) { + rT.reason.append(", COBpredBG " + convert_bg(lastCOBpredBG.toDouble())) + } + if (lastUAMpredBG != null) { + rT.reason.append(", UAMpredBG " + convert_bg(lastUAMpredBG.toDouble())) + } + rT.reason.append("; ") + // use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39 + var carbsReqBG = naive_eventualBG + if (carbsReqBG < 40) { + carbsReqBG = min(minGuardBG, carbsReqBG) + } + var bgUndershoot: Double = threshold - carbsReqBG + // calculate how long until COB (or IOB) predBGs drop below min_bg + var minutesAboveMinBG = 240 + var minutesAboveThreshold = 240 + if (meal_data.mealCOB > 0 && (ci > 0 || remainingCIpeak > 0)) { + for (i in COBpredBGs.indices) { + //console.error(COBpredBGs[i], min_bg); + if (COBpredBGs[i] < min_bg) { + minutesAboveMinBG = 5 * i + break + } + } + for (i in COBpredBGs.indices) { + //console.error(COBpredBGs[i], threshold); + if (COBpredBGs[i] < threshold) { + minutesAboveThreshold = 5 * i + break + } + } + } else { + for (i in IOBpredBGs.indices) { + //console.error(IOBpredBGs[i], min_bg); + if (IOBpredBGs[i] < min_bg) { + minutesAboveMinBG = 5 * i + break + } + } + for (i in IOBpredBGs.indices) { + //console.error(IOBpredBGs[i], threshold); + if (IOBpredBGs[i] < threshold) { + minutesAboveThreshold = 5 * i + break + } + } + } + + if (enableSMB && minGuardBG < threshold) { + consoleError.add("minGuardBG ${convert_bg(minGuardBG)} projected below ${convert_bg(threshold)} - disabling SMB") + //rT.reason += "minGuardBG "+minGuardBG+"<"+threshold+": SMB disabled; "; + enableSMB = false + } + if (maxDelta > 0.20 * bg) { + consoleError.add("maxDelta ${convert_bg(maxDelta)} > 20% of BG ${convert_bg(bg)} - disabling SMB") + rT.reason.append("maxDelta " + convert_bg(maxDelta) + " > 20% of BG " + convert_bg(bg) + ": SMB disabled; ") + enableSMB = false + } + + consoleError.add("BG projected to remain above ${convert_bg(min_bg)} for $minutesAboveMinBG minutes") + if (minutesAboveThreshold < 240 || minutesAboveMinBG < 60) { + consoleError.add("BG projected to remain above ${convert_bg(threshold)} for $minutesAboveThreshold minutes") + } + // include at least minutesAboveThreshold worth of zero temps in calculating carbsReq + // always include at least 30m worth of zero temp (carbs to 80, low temp up to target) + val zeroTempDuration = minutesAboveThreshold + // BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB + val zeroTempEffectDouble = profile.current_basal * sens * zeroTempDuration / 60 + // don't count the last 25% of COB against carbsReq + val COBforCarbsReq = max(0.0, meal_data.mealCOB - 0.25 * meal_data.carbs) + val carbsReq = round(((bgUndershoot - zeroTempEffectDouble) / csf - COBforCarbsReq)) + val zeroTempEffect = round(zeroTempEffectDouble) + consoleError.add("naive_eventualBG: $naive_eventualBG bgUndershoot: $bgUndershoot zeroTempDuration $zeroTempDuration zeroTempEffect: $zeroTempEffect carbsReq: $carbsReq") + if (carbsReq >= profile.carbsReqThreshold && minutesAboveThreshold <= 45) { + rT.carbsReq = carbsReq + rT.carbsReqWithin = minutesAboveThreshold + rT.reason.append("$carbsReq add\'l carbs req w/in ${minutesAboveThreshold}m; ") + } + + // don't low glucose suspend if IOB is already super negative and BG is rising faster than predicted + if (bg < threshold && iob_data.iob < -profile.current_basal * 20 / 60 && minDelta > 0 && minDelta > expectedDelta) { + rT.reason.append("IOB ${iob_data.iob} < ${round(-profile.current_basal * 20 / 60, 2)}") + rT.reason.append(" and minDelta ${convert_bg(minDelta)} > expectedDelta ${convert_bg(expectedDelta)}; ") + // predictive low glucose suspend mode: BG is / is projected to be < threshold + } else if (bg < threshold || minGuardBG < threshold) { + rT.reason.append("minGuardBG " + convert_bg(minGuardBG) + "<" + convert_bg(threshold)) + bgUndershoot = target_bg - minGuardBG + val worstCaseInsulinReq = bgUndershoot / sens + var durationReq = round(60 * worstCaseInsulinReq / profile.current_basal) + durationReq = round(durationReq / 30.0) * 30 + // always set a 30-120m zero temp (oref0-pump-loop will let any longer SMB zero temp run) + durationReq = min(120, max(30, durationReq)) + return setTempBasal(0.0, durationReq, profile, rT, currenttemp) + } + + // if not in LGS mode, cancel temps before the top of the hour to reduce beeping/vibration + // console.error(profile.skip_neutral_temps, rT.deliverAt.getMinutes()); + val minutes = Instant.ofEpochMilli(rT.deliverAt!!).atZone(ZoneId.systemDefault()).toLocalDateTime().minute + if (profile.skip_neutral_temps && minutes >= 55) { + rT.reason.append("; Canceling temp at " + minutes + "m past the hour. ") + return setTempBasal(0.0, 0, profile, rT, currenttemp) + } + + if (eventualBG < min_bg) { // if eventual BG is below target: + rT.reason.append("Eventual BG ${convert_bg(eventualBG)} < ${convert_bg(min_bg)}") + // if 5m or 30m avg BG is rising faster than expected delta + if (minDelta > expectedDelta && minDelta > 0 && carbsReq == 0) { + // if naive_eventualBG < 40, set a 30m zero temp (oref0-pump-loop will let any longer SMB zero temp run) + if (naive_eventualBG < 40) { + rT.reason.append(", naive_eventualBG < 40. ") + return setTempBasal(0.0, 30, profile, rT, currenttemp) + } + if (glucose_status.delta > minDelta) { + rT.reason.append(", but Delta ${convert_bg(tick.toDouble())} > expectedDelta ${convert_bg(expectedDelta)}") + } else { + rT.reason.append(", but Min. Delta ${minDelta.toFixed2()} > Exp. Delta ${convert_bg(expectedDelta)}") + } + if (currenttemp.duration > 15 && (round_basal(basal) == round_basal(currenttemp.rate))) { + rT.reason.append(", temp " + currenttemp.rate + " ~ req " + round(basal, 2).withoutZeros() + "U/hr. ") + return rT + } else { + rT.reason.append("; setting current basal of ${round(basal, 2)} as temp. ") + return setTempBasal(basal, 30, profile, rT, currenttemp) + } + } + + // calculate 30m low-temp required to get projected BG up to target + // multiply by 2 to low-temp faster for increased hypo safety + var insulinReq = + if (dynIsfMode) 2 * min(0.0, (eventualBG - target_bg) / future_sens) + else 2 * min(0.0, (eventualBG - target_bg) / sens) + insulinReq = round(insulinReq, 2) + // calculate naiveInsulinReq based on naive_eventualBG + var naiveInsulinReq = min(0.0, (naive_eventualBG - target_bg) / sens) + naiveInsulinReq = round(naiveInsulinReq, 2) + if (minDelta < 0 && minDelta > expectedDelta) { + // if we're barely falling, newinsulinReq should be barely negative + val newinsulinReq = round((insulinReq * (minDelta / expectedDelta)), 2) + //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); + insulinReq = newinsulinReq + } + // rate required to deliver insulinReq less insulin over 30m: + var rate = basal + (2 * insulinReq) + rate = round_basal(rate) + + // if required temp < existing temp basal + val insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60 + // if current temp would deliver a lot (30% of basal) less than the required insulin, + // by both normal and naive calculations, then raise the rate + val minInsulinReq = Math.min(insulinReq, naiveInsulinReq) + if (insulinScheduled < minInsulinReq - basal * 0.3) { + rT.reason.append(", ${currenttemp.duration}m@${(currenttemp.rate).toFixed2()} is a lot less than needed. ") + return setTempBasal(rate, 30, profile, rT, currenttemp) + } + if (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8) { + rT.reason.append(", temp ${currenttemp.rate} ~< req ${round(rate, 2)}U/hr. ") + return rT + } else { + // calculate a long enough zero temp to eventually correct back up to target + if (rate <= 0) { + bgUndershoot = (target_bg - naive_eventualBG) + val worstCaseInsulinReq = bgUndershoot / sens + var durationReq = round(60 * worstCaseInsulinReq / profile.current_basal) + if (durationReq < 0) { + durationReq = 0 + // don't set a temp longer than 120 minutes + } else { + durationReq = round(durationReq / 30.0) * 30 + durationReq = min(120, max(0, durationReq)) + } + //console.error(durationReq); + if (durationReq > 0) { + rT.reason.append(", setting ${durationReq}m zero temp. ") + return setTempBasal(rate, durationReq, profile, rT, currenttemp) + } + } else { + rT.reason.append(", setting ${round(rate, 2)}U/hr. ") + } + return setTempBasal(rate, 30, profile, rT, currenttemp) + } + } + + // if eventual BG is above min but BG is falling faster than expected Delta + if (minDelta < expectedDelta) { + // if in SMB mode, don't cancel SMB zero temp + if (!(microBolusAllowed && enableSMB)) { + if (glucose_status.delta < minDelta) { + rT.reason.append( + "Eventual BG ${convert_bg(eventualBG)} > ${convert_bg(min_bg)} but Delta ${convert_bg(tick.toDouble())} < Exp. Delta ${ + convert_bg(expectedDelta) + }" + ) + } else { + rT.reason.append("Eventual BG ${convert_bg(eventualBG)} > ${convert_bg(min_bg)} but Min. Delta ${minDelta.toFixed2()} < Exp. Delta ${convert_bg(expectedDelta)}") + } + if (currenttemp.duration > 15 && (round_basal(basal) == round_basal(currenttemp.rate))) { + rT.reason.append(", temp " + currenttemp.rate + " ~ req " + round(basal, 2).withoutZeros() + "U/hr. ") + return rT + } else { + rT.reason.append("; setting current basal of ${round(basal, 2)} as temp. ") + return setTempBasal(basal, 30, profile, rT, currenttemp) + } + } + } + // eventualBG or minPredBG is below max_bg + if (min(eventualBG, minPredBG) < max_bg) { + // if in SMB mode, don't cancel SMB zero temp + if (!(microBolusAllowed && enableSMB)) { + rT.reason.append("${convert_bg(eventualBG)}-${convert_bg(minPredBG)} in range: no temp required") + if (currenttemp.duration > 15 && (round_basal(basal) == round_basal(currenttemp.rate))) { + rT.reason.append(", temp ${currenttemp.rate} ~ req ${round(basal, 2).withoutZeros()}U/hr. ") + return rT + } else { + rT.reason.append("; setting current basal of ${round(basal, 2)} as temp. ") + return setTempBasal(basal, 30, profile, rT, currenttemp) + } + } + } + + // eventual BG is at/above target + // if iob is over max, just cancel any temps + if (eventualBG >= max_bg) { + rT.reason.append("Eventual BG " + convert_bg(eventualBG) + " >= " + convert_bg(max_bg) + ", ") + } + if (iob_data.iob > max_iob) { + rT.reason.append("IOB ${round(iob_data.iob, 2)} > max_iob $max_iob") + if (currenttemp.duration > 15 && (round_basal(basal) == round_basal(currenttemp.rate))) { + rT.reason.append(", temp ${currenttemp.rate} ~ req ${round(basal, 2).withoutZeros()}U/hr. ") + return rT + } else { + rT.reason.append("; setting current basal of ${round(basal, 2)} as temp. ") + return setTempBasal(basal, 30, profile, rT, currenttemp) + } + } else { // otherwise, calculate 30m high-temp required to get projected BG down to target + // insulinReq is the additional insulin required to get minPredBG down to target_bg + //console.error(minPredBG,eventualBG); + var insulinReq = + if (dynIsfMode) round((min(minPredBG, eventualBG) - target_bg) / future_sens, 2) + else round((min(minPredBG, eventualBG) - target_bg) / sens, 2) + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob - iob_data.iob) { + rT.reason.append("max_iob $max_iob, ") + insulinReq = max_iob - iob_data.iob + } + + // rate required to deliver insulinReq more insulin over 30m: + var rate = basal + (2 * insulinReq) + rate = round_basal(rate) + insulinReq = round(insulinReq, 3) + rT.insulinReq = insulinReq + //console.error(iob_data.lastBolusTime); + // minutes since last bolus + val lastBolusAge = round((systemTime - iob_data.lastBolusTime) / 60000.0, 1) + //console.error(lastBolusAge); + //console.error(profile.temptargetSet, target_bg, rT.COB); + // only allow microboluses with COB or low temp targets, or within DIA hours of a bolus + val maxBolus: Double + if (microBolusAllowed && enableSMB && bg > threshold) { + // never bolus more than maxSMBBasalMinutes worth of basal + val mealInsulinReq = round(meal_data.mealCOB / profile.carb_ratio, 3) + if (iob_data.iob > mealInsulinReq && iob_data.iob > 0) { + consoleError.add("IOB ${iob_data.iob} > COB ${meal_data.mealCOB}; mealInsulinReq = $mealInsulinReq") + consoleError.add("profile.maxUAMSMBBasalMinutes: ${profile.maxUAMSMBBasalMinutes} profile.current_basal: ${profile.current_basal}") + maxBolus = round(profile.current_basal * profile.maxUAMSMBBasalMinutes / 60, 1) + } else { + consoleError.add("profile.maxSMBBasalMinutes: ${profile.maxSMBBasalMinutes} profile.current_basal: ${profile.current_basal}") + maxBolus = round(profile.current_basal * profile.maxSMBBasalMinutes / 60, 1) + } + // bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment + val roundSMBTo = 1 / profile.bolus_increment + val microBolus = Math.floor(Math.min(insulinReq / 2, maxBolus) * roundSMBTo) / roundSMBTo + // calculate a long enough zero temp to eventually correct back up to target + val smbTarget = target_bg + val worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG) / 2.0) / sens + var durationReq = round(60 * worstCaseInsulinReq / profile.current_basal) + + // if insulinReq > 0 but not enough for a microBolus, don't set an SMB zero temp + if (insulinReq > 0 && microBolus < profile.bolus_increment) { + durationReq = 0 + } + + var smbLowTempReq = 0.0 + if (durationReq <= 0) { + durationReq = 0 + // don't set an SMB zero temp longer than 60 minutes + } else if (durationReq >= 30) { + durationReq = round(durationReq / 30.0) * 30 + durationReq = min(60, max(0, durationReq)) + } else { + // if SMB durationReq is less than 30m, set a nonzero low temp + smbLowTempReq = round(basal * durationReq / 30.0, 2) + durationReq = 30 + } + rT.reason.append(" insulinReq $insulinReq") + if (microBolus >= maxBolus) { + rT.reason.append("; maxBolus $maxBolus") + } + if (durationReq > 0) { + rT.reason.append("; setting ${durationReq}m low temp of ${smbLowTempReq}U/h") + } + rT.reason.append(". ") + + // allow SMBIntervals between 1 and 10 minutes + val SMBInterval = min(10, max(1, profile.SMBInterval)) + val nextBolusMins = round(SMBInterval - lastBolusAge, 0) + val nextBolusSeconds = round((SMBInterval - lastBolusAge) * 60, 0) % 60 + //console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq); + consoleError.add("naive_eventualBG $naive_eventualBG,${durationReq}m ${smbLowTempReq}U/h temp needed; last bolus ${lastBolusAge}m ago; maxBolus: $maxBolus") + if (lastBolusAge > SMBInterval) { + if (microBolus > 0) { + rT.units = microBolus + rT.reason.append("Microbolusing ${microBolus}U. ") + } + } else { + rT.reason.append("Waiting " + nextBolusMins + "m " + nextBolusSeconds + "s to microbolus again. ") + } + //rT.reason += ". "; + + // if no zero temp is required, don't return yet; allow later code to set a high temp + if (durationReq > 0) { + rT.rate = smbLowTempReq + rT.duration = durationReq + return rT + } + + } + + val maxSafeBasal = getMaxSafeBasal(profile) + + if (rate > maxSafeBasal) { + rT.reason.append("adj. req. rate: ${round(rate, 2)} to maxSafeBasal: ${maxSafeBasal.withoutZeros()}, ") + rate = round_basal(maxSafeBasal) + } + + val insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60 + if (insulinScheduled >= insulinReq * 2) { // if current temp would deliver >2x more than the required insulin, lower the rate + rT.reason.append("${currenttemp.duration}m@${(currenttemp.rate).toFixed2()} > 2 * insulinReq. Setting temp basal of ${round(rate, 2)}U/hr. ") + return setTempBasal(rate, 30, profile, rT, currenttemp) + } + + if (currenttemp.duration == 0) { // no temp is set + rT.reason.append("no temp, setting " + round(rate, 2).withoutZeros() + "U/hr. ") + return setTempBasal(rate, 30, profile, rT, currenttemp) + } + + if (currenttemp.duration > 5 && (round_basal(rate) <= round_basal(currenttemp.rate))) { // if required temp <~ existing temp basal + rT.reason.append("temp ${(currenttemp.rate).toFixed2()} >~ req ${round(rate, 2).withoutZeros()}U/hr. ") + return rT + } + + // required temp > existing temp basal + rT.reason.append("temp ${currenttemp.rate.toFixed2()} < ${round(rate, 2).withoutZeros()}U/hr. ") + return setTempBasal(rate, 30, profile, rT, currenttemp) + } + } +} diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt new file mode 100644 index 00000000000..2e68ed32550 --- /dev/null +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -0,0 +1,490 @@ +package app.aaps.plugins.aps.openAPSAutoISF + +import android.util.LongSparseArray +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreference +import app.aaps.core.data.aps.SMBDefaults +import app.aaps.core.data.model.GlucoseUnit +import app.aaps.core.data.plugin.PluginDescription +import app.aaps.core.data.plugin.PluginType +import app.aaps.core.data.time.T +import app.aaps.core.interfaces.aps.APS +import app.aaps.core.interfaces.aps.APSResult +import app.aaps.core.interfaces.aps.AutosensResult +import app.aaps.core.interfaces.aps.CurrentTemp +import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck +import app.aaps.core.interfaces.configuration.Config +import app.aaps.core.interfaces.constraints.Constraint +import app.aaps.core.interfaces.constraints.ConstraintsChecker +import app.aaps.core.interfaces.constraints.PluginConstraints +import app.aaps.core.interfaces.db.PersistenceLayer +import app.aaps.core.interfaces.db.ProcessedTbrEbData +import app.aaps.core.interfaces.iob.GlucoseStatusProvider +import app.aaps.core.interfaces.iob.IobCobCalculator +import app.aaps.core.interfaces.logging.AAPSLogger +import app.aaps.core.interfaces.logging.LTag +import app.aaps.core.interfaces.notifications.Notification +import app.aaps.core.interfaces.plugin.ActivePlugin +import app.aaps.core.interfaces.plugin.PluginBase +import app.aaps.core.interfaces.profile.Profile +import app.aaps.core.interfaces.profile.ProfileFunction +import app.aaps.core.interfaces.profile.ProfileUtil +import app.aaps.core.interfaces.profiling.Profiler +import app.aaps.core.interfaces.resources.ResourceHelper +import app.aaps.core.interfaces.rx.bus.RxBus +import app.aaps.core.interfaces.rx.events.EventAPSCalculationFinished +import app.aaps.core.interfaces.stats.TddCalculator +import app.aaps.core.interfaces.ui.UiInteraction +import app.aaps.core.interfaces.utils.DateUtil +import app.aaps.core.interfaces.utils.HardLimits +import app.aaps.core.interfaces.utils.Round +import app.aaps.core.keys.BooleanKey +import app.aaps.core.keys.DoubleKey +import app.aaps.core.keys.IntKey +import app.aaps.core.keys.Preferences +import app.aaps.core.keys.UnitDoubleKey +import app.aaps.core.objects.aps.DetermineBasalResult +import app.aaps.core.objects.constraints.ConstraintObject +import app.aaps.core.objects.extensions.convertedToAbsolute +import app.aaps.core.objects.extensions.getPassedDurationToTimeInMinutes +import app.aaps.core.objects.extensions.plannedRemainingMinutes +import app.aaps.core.objects.extensions.put +import app.aaps.core.objects.extensions.store +import app.aaps.core.objects.extensions.target +import app.aaps.core.utils.MidnightUtils +import app.aaps.plugins.aps.OpenAPSFragment +import app.aaps.plugins.aps.R +import app.aaps.plugins.aps.events.EventOpenAPSUpdateGui +import app.aaps.plugins.aps.events.EventResetOpenAPSGui +import app.aaps.plugins.aps.openAPS.TddStatus +import dagger.android.HasAndroidInjector +import org.json.JSONObject +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.floor +import kotlin.math.ln + +@Singleton +open class OpenAPSAutoISFPlugin @Inject constructor( + private val injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + private val rxBus: RxBus, + private val constraintsChecker: ConstraintsChecker, + rh: ResourceHelper, + private val profileFunction: ProfileFunction, + private val profileUtil: ProfileUtil, + config: Config, + private val activePlugin: ActivePlugin, + private val iobCobCalculator: IobCobCalculator, + private val hardLimits: HardLimits, + private val preferences: Preferences, + protected val dateUtil: DateUtil, + private val processedTbrEbData: ProcessedTbrEbData, + private val persistenceLayer: PersistenceLayer, + private val glucoseStatusProvider: GlucoseStatusProvider, + private val tddCalculator: TddCalculator, + private val bgQualityCheck: BgQualityCheck, + private val uiInteraction: UiInteraction, + private val determineBasalAutoISF: DetermineBasalAutoISF, + private val profiler: Profiler, +) : PluginBase( + PluginDescription() + .mainType(PluginType.APS) + .fragmentClass(OpenAPSFragment::class.java.name) + .pluginIcon(app.aaps.core.ui.R.drawable.ic_generic_icon) + .pluginName(R.string.openaps_auto_isf) + .shortName(R.string.autoisf_shortname) + .preferencesId(R.xml.pref_openapsautoisf) + .preferencesVisibleInSimpleMode(true) + .showInList(config.APS) + .description(R.string.description_auto_isf), + aapsLogger, rh +), APS, PluginConstraints { + + // last values + override var lastAPSRun: Long = 0 + override val algorithm = APSResult.Algorithm.SMB + override var lastAPSResult: DetermineBasalResult? = null + override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) + + override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { + val start = dateUtil.now() + val sensitivity = calculateVariableIsf(start, bg = null) + if (sensitivity.second == null) + uiInteraction.addNotificationValidTo( + Notification.DYN_ISF_FALLBACK, start, + rh.gs(R.string.fallback_to_isf_no_tdd), Notification.INFO, dateUtil.now() + T.mins(1).msecs() + ) + else + uiInteraction.dismissNotification(Notification.DYN_ISF_FALLBACK) + profiler.log(LTag.APS, String.format("getIsfMgdl() %s %f %s %s", sensitivity.first, sensitivity.second, dateUtil.dateAndTimeAndSecondsString(start), caller), start) + return sensitivity.second?.let { it * multiplier } + } + + override fun getIsfMgdl(timestamp: Long, bg: Double, multiplier: Double, timeShift: Int, caller: String): Double? { + val start = dateUtil.now() + val sensitivity = calculateVariableIsf(timestamp, bg) + profiler.log(LTag.APS, String.format("getIsfMgdl() %s %f %s %s", sensitivity.first, sensitivity.second, dateUtil.dateAndTimeAndSecondsString(timestamp), caller), start) + return sensitivity.second?.let { it * multiplier } + } + + override fun specialEnableCondition(): Boolean { + return try { + activePlugin.activePump.pumpDescription.isTempBasalCapable + } catch (ignored: Exception) { + // may fail during initialization + true + } + } + + override fun specialShowInListCondition(): Boolean { + val pump = activePlugin.activePump + return pump.pumpDescription.isTempBasalCapable + } + + override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) { + super.preprocessPreferences(preferenceFragment) + val smbAlwaysEnabled = preferences.get(BooleanKey.ApsUseSmbAlways) + val advancedFiltering = activePlugin.activeBgSource.advancedFilteringSupported() + preferenceFragment.findPreference(rh.gs(app.aaps.core.keys.R.string.key_openaps_allow_smb_with_COB))?.isVisible = !smbAlwaysEnabled || !advancedFiltering + preferenceFragment.findPreference(rh.gs(app.aaps.core.keys.R.string.key_openaps_allow_smb_with_low_temp_target))?.isVisible = !smbAlwaysEnabled || !advancedFiltering + preferenceFragment.findPreference(rh.gs(app.aaps.core.keys.R.string.key_openaps_enable_smb_after_carbs))?.isVisible = !smbAlwaysEnabled || !advancedFiltering + } + + private val dynIsfCache = LongSparseArray() + private fun calculateVariableIsf(timestamp: Long, bg: Double?): Pair { + // Calculate here ISF value with AutoISF algo + if (!preferences.get(BooleanKey.ApsUseAutoIsf)) return Pair("OFF", null) + + val result = persistenceLayer.getApsResultCloseTo(timestamp) + if (result?.variableSens != null) { + //aapsLogger.debug("calculateVariableIsf $caller DB ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${result.variableSens}") + return Pair("DB", result.variableSens) + } + + val glucose = bg ?: glucoseStatusProvider.glucoseStatusData?.glucose ?: return Pair("GLUC", null) + // Round down to 30 min and use it as a key for caching + // Add BG to key as it affects calculation + val key = timestamp - timestamp % T.mins(30).msecs() + glucose.toLong() + val cached = dynIsfCache[key] + if (cached != null && timestamp < dateUtil.now()) { + //aapsLogger.debug("calculateVariableIsf $caller HIT ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $cached") + return Pair("HIT", cached) + } + + // no cached result found, let's calculate the value + val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 1, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) + val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 7, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) + val tddLast24H = tddCalculator.calculateDaily(-24, 0)?.totalAmount ?: return Pair("TDD miss", null) + val tddLast4H = tddCalculator.calculateDaily(-4, 0)?.totalAmount ?: return Pair("TDD miss", null) + val tddLast8to4H = tddCalculator.calculateDaily(-8, -4)?.totalAmount ?: return Pair("TDD miss", null) + val insulinDivisor = when { + activePlugin.activeInsulin.peak > 65 -> 55 // lyumjev peak: 45 + activePlugin.activeInsulin.peak > 50 -> 65 // ultra rapid peak: 55 + else -> 75 // rapid peak: 75 + } + val tddStatus = TddStatus(tdd1D, tdd7D, tddLast24H, tddLast4H, tddLast8to4H) + val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 + val tdd = (tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 + + val sensitivity = Round.roundTo(1800 / (tdd * (ln((glucose / insulinDivisor) + 1))), 0.1) + //aapsLogger.debug("calculateVariableIsf $caller CAL ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $sensitivity") + dynIsfCache.put(key, sensitivity) + if (dynIsfCache.size() > 1000) dynIsfCache.clear() + return Pair("CALC", sensitivity) + } + + override fun invoke(initiator: String, tempBasalFallback: Boolean) { + aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback") + lastAPSResult = null + val glucoseStatus = glucoseStatusProvider.glucoseStatusData + val profile = profileFunction.getProfile() + val pump = activePlugin.activePump + if (profile == null) { + rxBus.send(EventResetOpenAPSGui(rh.gs(app.aaps.core.ui.R.string.no_profile_set))) + aapsLogger.debug(LTag.APS, rh.gs(app.aaps.core.ui.R.string.no_profile_set)) + return + } + if (!isEnabled()) { + rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openapsma_disabled))) + aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_disabled)) + return + } + if (glucoseStatus == null) { + rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openapsma_no_glucose_data))) + aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_no_glucose_data)) + return + } + + val inputConstraints = ConstraintObject(0.0, aapsLogger) // fake. only for collecting all results + + if (!hardLimits.checkHardLimits(profile.dia, app.aaps.core.ui.R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return + if (!hardLimits.checkHardLimits( + profile.getIcTimeFromMidnight(MidnightUtils.secondsFromMidnight()), + app.aaps.core.ui.R.string.profile_carbs_ratio_value, + hardLimits.minIC(), + hardLimits.maxIC() + ) + ) return + if (!hardLimits.checkHardLimits(profile.getIsfMgdl("OpenAPSSMBPlugin"), app.aaps.core.ui.R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return + if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), app.aaps.core.ui.R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return + if (!hardLimits.checkHardLimits(pump.baseBasalRate, app.aaps.core.ui.R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return + + // End of check, start gathering data + + val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) + val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) + val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() + + val now = dateUtil.now() + val tb = processedTbrEbData.getTempBasalIncludingConvertedExtended(now) + val currentTemp = CurrentTemp( + duration = tb?.plannedRemainingMinutes ?: 0, + rate = tb?.convertedToAbsolute(now, profile) ?: 0.0, + minutesrunning = tb?.getPassedDurationToTimeInMinutes(now) + ) + var minBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetLowMgdl(), 0.1), app.aaps.core.ui.R.string.profile_low_target, HardLimits.LIMIT_MIN_BG[0], HardLimits.LIMIT_MIN_BG[1]) + var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.getTargetHighMgdl(), 0.1), app.aaps.core.ui.R.string.profile_high_target, HardLimits.LIMIT_MAX_BG[0], HardLimits.LIMIT_MAX_BG[1]) + var targetBg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TARGET_BG[0], HardLimits.LIMIT_TARGET_BG[1]) + var isTempTarget = false + persistenceLayer.getTemporaryTargetActiveAt(dateUtil.now())?.let { tempTarget -> + isTempTarget = true + minBg = hardLimits.verifyHardLimits(tempTarget.lowTarget, app.aaps.core.ui.R.string.temp_target_low_target, HardLimits.LIMIT_TEMP_MIN_BG[0], HardLimits.LIMIT_TEMP_MIN_BG[1]) + maxBg = hardLimits.verifyHardLimits(tempTarget.highTarget, app.aaps.core.ui.R.string.temp_target_high_target, HardLimits.LIMIT_TEMP_MAX_BG[0], HardLimits.LIMIT_TEMP_MAX_BG[1]) + targetBg = hardLimits.verifyHardLimits(tempTarget.target(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TEMP_TARGET_BG[0], HardLimits.LIMIT_TEMP_TARGET_BG[1]) + } + val insulin = activePlugin.activeInsulin + val insulinDivisor = when { + insulin.peak > 65 -> 55 // rapid peak: 75 + insulin.peak > 50 -> 65 // ultra rapid peak: 55 + else -> 75 // lyumjev peak: 45 + } + + var autosensResult = AutosensResult() + val tddStatus: TddStatus? + var variableSensitivity = 0.0 + var tdd = 0.0 + if (dynIsfMode) { + // DynamicISF specific + // without these values DynISF doesn't work properly + // Current implementation is fallback to SMB if TDD history is not available. Thus calculated here + val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(1, allowMissingDays = false))?.data?.totalAmount + val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(7, allowMissingDays = false)) + val tddLast24H = tddCalculator.calculateDaily(-24, 0) + val tddLast4H = tddCalculator.calculateDaily(-4, 0)?.totalAmount + val tddLast8to4H = tddCalculator.calculateDaily(-8, -4)?.totalAmount + if (tdd1D == null || tdd7D == null || tddLast4H == null || tddLast8to4H == null || tddLast24H == null) { + uiInteraction.addNotificationValidTo( + Notification.SMB_FALLBACK, dateUtil.now(), + rh.gs(R.string.fallback_smb_no_tdd), Notification.INFO, dateUtil.now() + T.mins(1).msecs() + ) + inputConstraints.copyReasons( + ConstraintObject(false, aapsLogger).also { + it.set(false, rh.gs(R.string.fallback_smb_no_tdd), this) + } + ) + inputConstraints.copyReasons( + ConstraintObject(false, aapsLogger).apply { set(true, "tdd1D=$tdd1D tdd7D=${tdd7D?.data?.totalAmount} tddLast4H=$tddLast4H tddLast8to4H=$tddLast8to4H tddLast24H=${tddLast24H?.totalAmount}", this) } + ) + } else { + uiInteraction.dismissNotification(Notification.SMB_FALLBACK) + tddStatus = TddStatus(tdd1D, tdd7D.data.totalAmount, tddLast24H.totalAmount, tddLast4H, tddLast8to4H) + val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 + tdd = ((tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33)) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 + variableSensitivity = Round.roundTo(1800 / (tdd * (ln((glucoseStatus.glucose / insulinDivisor) + 1))), 0.1) + + // Compare insulin consumption of last 24h with last 7 days average + val tddRatio = if (preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) tddLast24H.totalAmount / tdd7D.data.totalAmount else 1.0 + // Because consumed carbs affects total amount of insulin compensate final ratio by consumed carbs ratio + // take only 60% (expecting 40% basal). We cannot use bolus/total because of SMBs + val carbsRatio = if ( + preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity) && + tddLast24H.carbs != 0.0 && + tdd7D.data.carbs != 0.0 && + tdd7D.allDaysHaveCarbs + ) ((tddLast24H.carbs / tdd7D.data.carbs - 1.0) * 0.6) + 1.0 else 1.0 + autosensResult = AutosensResult( + ratio = tddRatio / carbsRatio, + ratioFromTdd = tddRatio, + ratioFromCarbs = carbsRatio + ) + } + } else { + if (constraintsChecker.isAutosensModeEnabled().value()) { + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") + if (autosensData == null) { + rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) + return + } + autosensResult = autosensData.autosensResult + } else autosensResult.sensResult = "autosens disabled" + } + + val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() + + val oapsProfile = OapsProfile( + dia = 0.0, // not used + min_5m_carbimpact = 0.0, // not used + max_iob = constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), + max_daily_basal = profile.getMaxDailyBasal(), + max_basal = constraintsChecker.getMaxBasalAllowed(profile).also { inputConstraints.copyReasons(it) }.value(), + min_bg = minBg, + max_bg = maxBg, + target_bg = targetBg, + carb_ratio = profile.getIc(), + sens = profile.getIsfMgdl("OpenAPSSMBPlugin"), + autosens_adjust_targets = false, // not used + max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), + current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), + lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), + high_temptarget_raises_sensitivity = false, + low_temptarget_lowers_sensitivity = false, + sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), + resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), + adv_target_adjustments = SMBDefaults.adv_target_adjustments, + exercise_mode = SMBDefaults.exercise_mode, + half_basal_exercise_target = SMBDefaults.half_basal_exercise_target, + maxCOB = SMBDefaults.maxCOB, + skip_neutral_temps = pump.setNeutralTempAtFullHour(), + remainingCarbsCap = SMBDefaults.remainingCarbsCap, + enableUAM = constraintsChecker.isUAMEnabled().also { inputConstraints.copyReasons(it) }.value(), + A52_risk_enable = SMBDefaults.A52_risk_enable, + SMBInterval = preferences.get(IntKey.ApsMaxSmbFrequency), + enableSMB_with_COB = smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithCob), + enableSMB_with_temptarget = smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithLowTt), + allowSMB_with_high_temptarget = smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithHighTt), + enableSMB_always = smbEnabled && preferences.get(BooleanKey.ApsUseSmbAlways) && advancedFiltering, + enableSMB_after_carbs = smbEnabled && preferences.get(BooleanKey.ApsUseSmbAfterCarbs) && advancedFiltering, + maxSMBBasalMinutes = preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb), + maxUAMSMBBasalMinutes = preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb), + bolus_increment = pump.pumpDescription.bolusStep, + carbsReqThreshold = preferences.get(IntKey.ApsCarbsRequestThreshold), + current_basal = activePlugin.activePump.baseBasalRate, + temptargetSet = isTempTarget, + autosens_max = preferences.get(DoubleKey.AutosensMax), + out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", + variable_sens = variableSensitivity, + insulinDivisor = insulinDivisor, + TDD = tdd + ) + + val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() + val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT + + aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal SMB <<<") + aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") + aapsLogger.debug(LTag.APS, "Current temp: $currentTemp") + aapsLogger.debug(LTag.APS, "IOB data: ${iobArray.joinToString()}") + aapsLogger.debug(LTag.APS, "Profile: $oapsProfile") + aapsLogger.debug(LTag.APS, "Autosens data: $autosensResult") + aapsLogger.debug(LTag.APS, "Meal data: $mealData") + aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") + aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") + aapsLogger.debug(LTag.APS, "DynIsfMode: $dynIsfMode") + + determineBasalAutoISF.determine_basal( + glucose_status = glucoseStatus, + currenttemp = currentTemp, + iob_data_array = iobArray, + profile = oapsProfile, + autosens_data = autosensResult, + meal_data = mealData, + microBolusAllowed = microBolusAllowed, + currentTime = now, + flatBGsDetected = flatBGsDetected, + dynIsfMode = dynIsfMode + ).also { + val determineBasalResult = DetermineBasalResult(injector, it) + // Preserve input data + determineBasalResult.inputConstraints = inputConstraints + determineBasalResult.autosensResult = autosensResult + determineBasalResult.iobData = iobArray + determineBasalResult.glucoseStatus = glucoseStatus + determineBasalResult.currentTemp = currentTemp + determineBasalResult.oapsProfile = oapsProfile + determineBasalResult.mealData = mealData + lastAPSResult = determineBasalResult + lastAPSRun = now + aapsLogger.debug(LTag.APS, "Result: $it") + rxBus.send(EventAPSCalculationFinished()) + } + + rxBus.send(EventOpenAPSUpdateGui()) + } + + override fun isSuperBolusEnabled(value: Constraint): Constraint { + value.set(false) + return value + } + + override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint { + if (isEnabled()) { + val maxIobPref = preferences.get(DoubleKey.ApsSmbMaxIob) + maxIob.setIfSmaller(maxIobPref, rh.gs(R.string.limiting_iob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this) + maxIob.setIfSmaller(hardLimits.maxIobSMB(), rh.gs(R.string.limiting_iob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this) + } + return maxIob + } + + override fun applyBasalConstraints(absoluteRate: Constraint, profile: Profile): Constraint { + if (isEnabled()) { + var maxBasal = preferences.get(DoubleKey.ApsMaxBasal) + if (maxBasal < profile.getMaxDailyBasal()) { + maxBasal = profile.getMaxDailyBasal() + absoluteRate.addReason(rh.gs(R.string.increasing_max_basal), this) + } + absoluteRate.setIfSmaller(maxBasal, rh.gs(app.aaps.core.ui.R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this) + + // Check percentRate but absolute rate too, because we know real current basal in pump + val maxBasalMultiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier) + val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.getBasal() * 100) / 100 + absoluteRate.setIfSmaller( + maxFromBasalMultiplier, + rh.gs(app.aaps.core.ui.R.string.limitingbasalratio, maxFromBasalMultiplier, rh.gs(R.string.max_basal_multiplier)), + this + ) + val maxBasalFromDaily = preferences.get(DoubleKey.ApsMaxDailyMultiplier) + val maxFromDaily = floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100 + absoluteRate.setIfSmaller(maxFromDaily, rh.gs(app.aaps.core.ui.R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.max_daily_basal_multiplier)), this) + } + return absoluteRate + } + + override fun isSMBModeEnabled(value: Constraint): Constraint { + val enabled = preferences.get(BooleanKey.ApsUseSmb) + if (!enabled) value.set(false, rh.gs(R.string.smb_disabled_in_preferences), this) + return value + } + + override fun isUAMEnabled(value: Constraint): Constraint { + val enabled = preferences.get(BooleanKey.ApsUseUam) + if (!enabled) value.set(false, rh.gs(R.string.uam_disabled_in_preferences), this) + return value + } + + override fun isAutosensModeEnabled(value: Constraint): Constraint { + if (preferences.get(BooleanKey.ApsUseAutoIsf)) { + // DynISF mode + if (!preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) + value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) + } else { + // SMB mode + val enabled = preferences.get(BooleanKey.ApsUseAutosens) + if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) + } + return value + } + + override fun configuration(): JSONObject = + JSONObject() + .put(BooleanKey.ApsUseAutoIsf, preferences, rh) + .put(IntKey.ApsDynIsfAdjustmentFactor, preferences, rh) + + override fun applyConfiguration(configuration: JSONObject) { + configuration + .store(BooleanKey.ApsUseAutoIsf, preferences, rh) + .store(IntKey.ApsDynIsfAdjustmentFactor, preferences, rh) + } +} \ No newline at end of file diff --git a/plugins/aps/src/main/res/values/strings.xml b/plugins/aps/src/main/res/values/strings.xml index bd534f1f5e7..203e83124d6 100644 --- a/plugins/aps/src/main/res/values/strings.xml +++ b/plugins/aps/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ OpenAPS SMB Dynamic ISF + Auto ISF How frequently SMBs will be given in min Resistance lowers target When resistance is detected, lower the target glucose @@ -19,6 +20,7 @@ No glucose data available No autosens data available DYNISF + AUTOISF Executing OpenAPS AMA Array of %1$d elements.\nActual value: @@ -26,6 +28,7 @@ State of the algorithm in 2017 Most recent algorithm for advanced users Most recent algorithm for advanced users with dynamic/automatic ISF + Most recent algorithm for advanced users with AutoISF extensions Bolus snooze dia divisor Run now @@ -129,5 +132,63 @@ Fallback to SMB. Not enough TDD data. Fallback to profile sensitivity. Not enough TDD data. + + Half basal exercise target + Set to a number, e.g. 160, which means when temp target is 160 mg/dL and High temptarget raises sensitivity=true, run 50% basal at this level (120 = 75%; 140 = 60%). + autoISF settings + autoISF allows to adapt the insulin sensitivity factor (ISF) in various scenarios of glucose behaviour\n\nIt can also adapt SMB delivery settings + acce_ISF settings + acce_ISF settings: adjust ISF for accelerating/decelerating blood glucose + Enable dura_ISF with COB + Enable dura_ISF when there is COB active + bg_ISF settings + bg_ISF settings: ISF depending on blood glucose level according to a predefined polygon + Enable the postprandial ISF adaptation all the time regardless of when the last meal was taken. + pp_ISF settings + pp_ISF settings: ISF for postprandial (after meal) glucose rise + delta_ISF settings + delta_ISF settings: ISF adaptations for positive delta, i.e. rising blood glucose + dura_ISF settings + dura_ISF settings: ISF for blood glucose plateau above target + smb delivery settings + smb delivery settings: Set of options to increase the actual SMB size which can be delivered in situations where ISF was strengthened, i.e. fairly low ISF figure.\n\nUSE WITH CAUTION + Enable ISF adaptation by glucose behaviour + Default value: 1.2\nThis is a multiplier cap for autoISF to set a limit on how high the autoISF ratio can be, which in turn determines how low it can adjust ISF.\n\nWARNING: Be extremely careful when using values above 2.5 + Default value: 1.0\nThis 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. + Default value: 0.0\nThis is the rate at which autoISF grows per hour assuming bg is twice the target. With a value of 1.0 it will have reduced ISF to 50% after 1 hour of bg at twice the target.\n\nWith 0.0 the effect of autoISF is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF if glucose is below target. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF if glucose is above target. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF for higher deltas. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the linear slope while glucose rises and which adapts ISF. \n\nWith 0.0 this contribution is effectively disabled. + Default value: 3\nThis is the duration in hours how long after a meal the effect will be active. \n\nAAPS will delete carb timing after 10 hours latest no matter what you enter. + Enable pp_ISF postprandial all day + Default value: 0.0\nThis is the weight applied while glucose accelerates and which strengthens ISF. \n\nWith 0.0 this contribution is effectively disabled. + Default value: 0.0\nThis is the weight applied while glucose decelerates and which weakens ISF. \n\nWith 0.0 this contribution is effectively disabled. + Max autoISF ratio\n(autoISF_max) + Min autoISF ratio\n(autoISF_min) + lower ISF-range weight\n(lower_ISFrange_weight) + higher ISF-range weight\n(higher_ISFrange_weight) + delta ISF-range weight\n(delta_ISFrange_weight) + postprandial ISF weight\n(pp_ISF_weight) + postprandial ISF time window\n(pp_ISF_hours) + Weight while BG accelerates\n(bgAccel_ISF_weight) + Weight while BG decelerates\n(bgBrake_ISF_weight) + dura_ISF weight\n(dura_ISF_weight) + fixed SMB delivery ratio\n(smb_delivery_ratio) + variable SMB delivery ratio, lower end\n(smb_delivery_ratio_min) + variable SMB delivery ratio, upper end\n(smb_delivery_ratio_max) + variable SMB delivery ratio, mapped glucose range\n(smb_delivery_ratio_bg_range) + SMB/UAM max range extension\n(smb_max_range_extension) + 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. + Default value: 0.5 This is the lower end of a linearly increasing ratio rather than the fix value above. + Default value: 0.5 This is the upper end of a linearly increasing ratio rather than the fix value above. + Default value: 0. The linearly increasing SMB delivery ratio is mapped to the glucose range [target_bg, target_bg+bg_range].\nAt target_bg the SMB ratio is smb_delivery_ratio_min, at target_bg+bg_range it is smb_delivery_ratio_max\nWith 0 the linearly increasing SMB ratio is disabled and the fixed smb_delivery_ratio is used. + 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. + Enable alternative activation of SMB depending on TempTarget + \nenabled if ...\nTempTarget(mmol/L) has even decimal\nor TempTarget(mg/dL) is even number\n\ndisabled otherwise + Enable alternative activation of SMB depending on profile target + \nenabled if no TempTarget set and ...\nprofile target(mmol/L) has even decimal\nor profile target(mg/dL) is even number\n\ndisabled otherwise + Default value: 100%\nWith 100% this feature is effectively disabled. + Percentage of maxIOB above which SMBs are disabled\n(iob_threshold_percent) diff --git a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml new file mode 100644 index 00000000000..d6be546c34a --- /dev/null +++ b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b8f4cd4843e0ef78dd1ee99a3226f06cd98e6917 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Wed, 14 Feb 2024 00:00:07 +0100 Subject: [PATCH 02/38] AutoISF keys --- .../kotlin/app/aaps/core/keys/BooleanKey.kt | 14 +++++----- .../kotlin/app/aaps/core/keys/DoubleKey.kt | 26 +++++++++---------- .../main/kotlin/app/aaps/core/keys/IntKey.kt | 5 ++-- .../app/aaps/core/keys/UnitDoubleKey.kt | 1 - 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt index b00c4bb728f..516f49825c6 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt @@ -44,11 +44,11 @@ enum class BooleanKey( ApsAmaAutosensAdjustTargets(R.string.key_openaps_ama_autosens_adjust_targets, true, defaultedBySM = true), ApsUseDynamicSensitivity(R.string.key_use_dynamic_sensitivity, false), MaintenanceEnableFabric(R.string.key_enable_fabric, true, defaultedBySM = true, hideParentScreenIfHidden = true), - ApsAutoIsfHighTtRaisesSens(R.string.key_high_temptarget_raises_sensitivity, false), - ApsAutoIsfLowTtLowersSens(R.string.key_low_temptarget_lowers_sensitivity, false), - ApsUseAutoIsf(R.string.key_enable_autoISF, false, defaultedBySM = true), - ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false), - ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false), - ApsAutoIsfSmbOnEvenTt(R.string.key_enableSMB_EvenOn_OddOff, false), // TempTarget - ApsAutoIsfSmbOnEvenPt(R.string.key_enableSMB_EvenOn_OddOff_always, false) // profile target + ApsAutoIsfHighTtRaisesSens(R.string.key_high_temptarget_raises_sensitivity, false, defaultedBySM = true), + ApsAutoIsfLowTtLowersSens(R.string.key_low_temptarget_lowers_sensitivity, false, defaultedBySM = true), + ApsUseAutoIsfWeights(R.string.key_enable_autoISF, false, defaultedBySM = true), + ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false, defaultedBySM = true), + ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false, defaultedBySM = true), + ApsAutoIsfSmbOnEvenTt(R.string.key_enableSMB_EvenOn_OddOff, false, defaultedBySM = true), // TempTarget + ApsAutoIsfSmbOnEvenPt(R.string.key_enableSMB_EvenOn_OddOff_always, false, defaultedBySM = true) // profile target } \ No newline at end of file diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt index e3d3c0dca13..dfba0230a8d 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt @@ -34,19 +34,19 @@ enum class DoubleKey( AbsorptionMaxTime(R.string.key_absorption_maxtime, 6.0, 4.0, 10.0), AutosensMin(R.string.key_openaps_autosens_min, 0.7, 0.1, 1.0, defaultedBySM = true, hideParentScreenIfHidden = true), AutosensMax(R.string.key_openaps_autosens_max, 1.2, 0.5, 3.0, defaultedBySM = true), - ApsAutoIsfMin(R.string.key_openapsama_autoISF_min, 1.0, 0.3, 1.0, defaultedBySM = true), - ApsAutoIsfMax(R.string.key_openapsama_autoISF_max, 1.0, 1.0, 5.0, defaultedBySM = true), - ApsAutoIsfBgAccelWeight(R.string.key_openapsama_bgAccel_ISF_weight, 0.0, 0.0, 1.0), - ApsAutoIsfBgBrakeWeight(R.string.key_openapsama_bgBrake_ISF_weight, 0.0, 0.0, 1.0), - ApsAutoIsfLowBgWeight(R.string.key_openapsama_lower_ISFrange_weight, 0.0, 0.0, 2.0), - ApsAutoIsfHighBgWeight(R.string.key_openapsama_higher_ISFrange_weight, 0.0, 0.0, 2.0), - ApsAutoIsfPpWeight(R.string.key_openapsama_pp_ISF_weight, 0.0, 0.0, 1.0), - ApsAutoIsfDeltaWeight(R.string.key_openapsama_delta_ISFrange_weight, 0.0, 0.0, 1.0), - ApsAutoIsfDuraWeight(R.string.key_openapsama_dura_ISF_weight, 0.0, 0.0, 3.0), - ApsAutoIsfSmbDeliveryRatio(R.string.key_openapsama_smb_delivery_ratio, 0.5, 0.5, 1.0), - ApsAutoIsfSmbDeliveryRatioMin(R.string.key_openapsama_smb_delivery_ratio_min, 0.5, 0.5, 1.0), - ApsAutoIsfSmbDeliveryRatioMax(R.string.key_openapsama_smb_delivery_ratio_max, 0.5, 0.5, 1.0), - ApsAutoIsfSmbMaxRangeExtension(R.string.key_openapsama_smb_max_range_extension, 1.0, 1.0, 5.0), + ApsAutoIsfMin(R.string.key_openapsama_autoISF_min, 1.0, 0.3, 1.0, defaultedBySM = false), + ApsAutoIsfMax(R.string.key_openapsama_autoISF_max, 1.0, 1.0, 5.0, defaultedBySM = false), + ApsAutoIsfBgAccelWeight(R.string.key_openapsama_bgAccel_ISF_weight, 0.0, 0.0, 1.0, defaultedBySM = true), + ApsAutoIsfBgBrakeWeight(R.string.key_openapsama_bgBrake_ISF_weight, 0.0, 0.0, 1.0, defaultedBySM = true), + ApsAutoIsfLowBgWeight(R.string.key_openapsama_lower_ISFrange_weight, 0.0, 0.0, 2.0, defaultedBySM = true), + ApsAutoIsfHighBgWeight(R.string.key_openapsama_higher_ISFrange_weight, 0.0, 0.0, 2.0, defaultedBySM = true), + ApsAutoIsfPpWeight(R.string.key_openapsama_pp_ISF_weight, 0.0, 0.0, 1.0, defaultedBySM = true), + ApsAutoIsfDeltaWeight(R.string.key_openapsama_delta_ISFrange_weight, 0.0, 0.0, 1.0, defaultedBySM = true), + ApsAutoIsfDuraWeight(R.string.key_openapsama_dura_ISF_weight, 0.0, 0.0, 3.0, defaultedBySM = true), + ApsAutoIsfSmbDeliveryRatio(R.string.key_openapsama_smb_delivery_ratio, 0.5, 0.5, 1.0, defaultedBySM = true), + ApsAutoIsfSmbDeliveryRatioMin(R.string.key_openapsama_smb_delivery_ratio_min, 0.5, 0.5, 1.0, defaultedBySM = true), + ApsAutoIsfSmbDeliveryRatioMax(R.string.key_openapsama_smb_delivery_ratio_max, 0.5, 0.5, 1.0, defaultedBySM = true), + ApsAutoIsfSmbMaxRangeExtension(R.string.key_openapsama_smb_max_range_extension, 1.0, 1.0, 5.0, defaultedBySM = true), EquilMaxBolus(R.string.key_equil_maxbolus, 10.0, 0.1, 25.0), } \ No newline at end of file diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt index 08a981b5cbf..d5e3a6e03de 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/IntKey.kt @@ -45,8 +45,9 @@ enum class IntKey( ApsMaxMinutesOfBasalToLimitSmb(R.string.key_openaps_smb_max_minutes, 30, 15, 120, defaultedBySM = true), ApsUamMaxMinutesOfBasalToLimitSmb(R.string.key_openaps_uam_smb_max_minutes, 30, 15, 120, defaultedBySM = true), ApsCarbsRequestThreshold(R.string.key_openaps_carbs_required_threshold, 1, 1, 10, defaultedBySM = true), - ApsAutoIsfPpIsfHours(R.string.key_openapsama_pp_ISF_hours, 3, 1, 10), - ApsAutoIsfIobThPercent(R.string.key_openapsama_iob_threshold_percent, 100, 10, 100), + ApsAutoIsfHalfBasalExerciseTarget(R.string.key_half_basal_exercise_target, 160, 120, 200, defaultedBySM = true), + ApsAutoIsfPpIsfHours(R.string.key_openapsama_pp_ISF_hours, 3, 1, 10, defaultedBySM = true), + ApsAutoIsfIobThPercent(R.string.key_openapsama_iob_threshold_percent, 100, 10, 100, defaultedBySM = true), ApsDynIsfAdjustmentFactor(R.string.key_dynamic_isf_adjustment_factor, 100, 1, 300, dependency = R.string.key_use_dynamic_sensitivity), AutosensPeriod(R.string.key_openapsama_autosens_period, 24, 4, 24, calculatedDefaultValue = true), MaintenanceLogsAmount(R.string.key_maintenance_logs_amount, 2, 1, 10, defaultedBySM = true), diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt index 5315c0ef377..59e37993b86 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/UnitDoubleKey.kt @@ -20,6 +20,5 @@ enum class UnitDoubleKey( OverviewLowMark(R.string.key_low_mark, 72.0, 25, 160, showInNsClientMode = false, hideParentScreenIfHidden = true), OverviewHighMark(R.string.key_high_mark, 180.0, 90, 250, showInNsClientMode = false), ApsLgsThreshold(R.string.key_dynamic_isf_lgs_threshold, 65.0, 65, 120, defaultedBySM = true, dependency = R.string.key_use_dynamic_sensitivity), - ApsAutoIsfHalfBasalExerciseTarget(R.string.key_half_basal_exercise_target, 160.0, 120, 200, defaultedBySM = true), ApsAutoIsfSmbDeliveryRatioBgRange(R.string.key_openapsama_smb_delivery_ratio_bg_range, 0.0, 0, 100, defaultedBySM = true) } \ No newline at end of file From 2f1a985995e25fc336fc2c53d58de4f88cb258c0 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Wed, 14 Feb 2024 00:46:44 +0100 Subject: [PATCH 03/38] AutoISF prefs --- .../src/main/res/xml/pref_openapsautoisf.xml | 187 +++++++++++++++++- 1 file changed, 179 insertions(+), 8 deletions(-) diff --git a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml index d6be546c34a..87b5fb7e5e9 100644 --- a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml +++ b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml @@ -17,6 +17,7 @@ android:key="@string/key_openaps_smb_max_iob" android:title="@string/openapssmb_max_iob_title" /> + - - + android:title="@string/low_temptarget_lowers_sensitivity_title" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2d4aefe57d40757db37f8bd603e75ee85546555b Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Wed, 14 Feb 2024 19:11:26 +0100 Subject: [PATCH 04/38] fixed half_basal_exercise_target data type --- plugins/aps/src/main/res/xml/pref_openapsautoisf.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml index 87b5fb7e5e9..a5f39854ba1 100644 --- a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml +++ b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml @@ -115,7 +115,7 @@ android:summary="@string/low_temptarget_lowers_sensitivity_summary" android:title="@string/low_temptarget_lowers_sensitivity_title" /> - From bad2c91fb97849d2d2dc568571a18a3939a95314 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Wed, 14 Feb 2024 19:15:20 +0100 Subject: [PATCH 05/38] AutoISF algo reduced from 3-in-1 to 2-in-1 --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 75 ++- .../aaps/core/interfaces/aps/OapsProfile.kt | 27 +- .../aps/openAPSAMA/OpenAPSAMAPlugin.kt | 25 +- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 510 +++++++++++++++--- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 78 ++- .../aps/openAPSSMB/OpenAPSSMBPlugin.kt | 27 +- 6 files changed, 640 insertions(+), 102 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 00659e5c278..48d7f0adfb7 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -211,7 +211,30 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = 0.0, insulinDivisor = 0, - TDD = 0.0 + TDD = 0.0, + autoISF_version = "", + enable_autoISF = false, + autoISF_max = 1.0, + autoISF_min = 1.0, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = false, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = false, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.0, + smb_delivery_ratio_min = 0.0, + smb_delivery_ratio_max = 0.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = false, + enableSMB_EvenOn_OddOff_always = false, + iob_threshold_percent = 100, + profile_percentage = 100 ) val meatData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), @@ -375,7 +398,30 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = determineBasalResult.profile.getDouble("variable_sens"), insulinDivisor = determineBasalResult.profile.getInt("insulinDivisor"), - TDD = determineBasalResult.profile.getDouble("TDD") + TDD = determineBasalResult.profile.getDouble("TDD"), + autoISF_version = "", + enable_autoISF = false, + autoISF_max = 1.0, + autoISF_min = 1.0, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = false, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = false, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.0, + smb_delivery_ratio_min = 0.0, + smb_delivery_ratio_max = 0.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = false, + enableSMB_EvenOn_OddOff_always = false, + iob_threshold_percent = 100, + profile_percentage = 100 ) val meatData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), @@ -533,7 +579,30 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = 0.0, insulinDivisor = 0, - TDD = 0.0 + TDD = 0.0, + autoISF_version = "", + enable_autoISF = false, + autoISF_max = 1.0, + autoISF_min = 1.0, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = false, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = false, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.0, + smb_delivery_ratio_min = 0.0, + smb_delivery_ratio_max = 0.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = false, + enableSMB_EvenOn_OddOff_always = false, + iob_threshold_percent = 100, + profile_percentage = 100 ) val mealData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt index 5dbbe01c4eb..d2fde971768 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt @@ -47,5 +47,30 @@ data class OapsProfile( //DynISF only var variable_sens: Double, var insulinDivisor: Int, - var TDD: Double + var TDD: Double, + //AutoISF only + var autoISF_version: String, + var enable_autoISF: Boolean, + var autoISF_max: Double, + var autoISF_min: Double, + var bgAccel_ISF_weight: Double, + var bgBrake_ISF_weight: Double, + var enable_pp_ISF_always: Boolean, + var pp_ISF_hours: Int, + var pp_ISF_weight: Double, + var delta_ISFrange_weight: Double, + var lower_ISFrange_weight: Double, + var higher_ISFrange_weight: Double, + var enable_dura_ISF_with_COB: Boolean, + var dura_ISF_weight: Double, + var smb_delivery_ratio: Double, + var smb_delivery_ratio_min: Double, + var smb_delivery_ratio_max: Double, + var smb_delivery_ratio_bg_range: Double, + var smb_max_range_extension: Double, + var enableSMB_EvenOn_OddOff: Boolean, + var enableSMB_EvenOn_OddOff_always: Boolean, + var iob_threshold_percent: Int, + var profile_percentage: Int + ) \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt index c0ff0d5e551..2cae5add910 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt @@ -214,7 +214,30 @@ class OpenAPSAMAPlugin @Inject constructor( out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = 0.0, // not used insulinDivisor = 0, // not used - TDD = 0.0 // not used + TDD = 0.0, // not used + autoISF_version = "", + enable_autoISF = false, + autoISF_max = 1.0, + autoISF_min = 1.0, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = false, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = false, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.0, + smb_delivery_ratio_min = 0.0, + smb_delivery_ratio_max = 0.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = false, + enableSMB_EvenOn_OddOff_always = false, + iob_threshold_percent = 100, + profile_percentage = 100 ) aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AMA <<<") diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 84dc4243c6e..c6d32299003 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -146,12 +146,354 @@ class DetermineBasalAutoISF @Inject constructor( } } + fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double) : String + { + if ( !microBolusAllowed ) { + return "AAPS" // see message in enable_smb + } + if (profile.temptargetSet && profile.enableSMB_EvenOn_OddOff || profile.min_bg==profile.max_bg && profile.enableSMB_EvenOn_OddOff_always && !profile.temptargetSet) { + var target = convert_bg(profile.target_bg) + var msgType: String + var evenTarget: Boolean + var msgUnits: String + var msgTail: String + var msgEven: String + var msg: String + if (profile.temptargetSet) { + msgType= "TempTarget" + } else { + msgType = "profile target" + } + if (profile.out_units == "mmol/L") { + evenTarget = (target.toDouble()*10.0).toInt() % 2 == 0 + msgUnits = "has " + msgTail = "decimal" + } else { + evenTarget = target.toInt() % 2 == 0 + msgUnits = "is " + msgTail = "number" + } + if ( evenTarget ) { + msgEven = "even " + } else { + msgEven = "odd " + } + var iobTHeffective = profile.iob_threshold_percent + if ( !evenTarget ) { + consoleError.add("SMB disabled; $msgType $target $msgUnits $msgEven $msgTail") + consoleError.add("Loop at minimum power") + return "blocked" + } else if ( profile.max_iob==0.0 ) { + consoleError.add("SMB disabled because of max_iob=0") + return "blocked" + } else if (iobTHeffective/100.0 < iob_data_iob/(profile.max_iob*iobTH_reduction_ratio)) { + if (iobTH_reduction_ratio != 1.0) { + consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob*iobTH_reduction_ratio,2)} due to profile % and/or exercise mode") + msg = "effective maxIOB ${round(profile.max_iob*iobTH_reduction_ratio,2)}" + } else { + msg = "maxIOB ${profile.max_iob}" + } + consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is more than $iobTHeffective% of $msg") + consoleError.add("Full Loop capped"); + return "iobTH"; + } else { + consoleError.add("SMB enabled; $msgType $target $msgUnits $msgEven $msgTail") + if (profile.target_bg<100) { // indirect assessment; later set it in GUI + consoleError.add("Loop at full power") + return "fullLoop" // even number + } else { + consoleError.add("Loop at medium power") + return "enforced" // even number + } + } + } + consoleError.add("Full Loop disabled") + return "AAPS" // leave it to standard AAPS + } + + fun interpolate(xdata: Double, profile: OapsProfile, type: String): Double + { // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... + val polyX: Array + val polyY: Array + if (type == "bg") { + // ... <---------------------- glucose ----------------------> + polyX = arrayOf(50.0, 60.0, 80.0, 90.0, 100.0, 110.0, 150.0, 180.0, 200.0) + polyY = arrayOf(-0.5, -0.5, -0.3, -0.2, 0.0, 0.0, 0.5, 0.7, 0.7) + } else { + // ... <------- delta --------> + polyX = arrayOf(2.0, 7.0, 12.0, 16.0, 20.0) + polyY = arrayOf(0.0, 0.0, 0.4, 0.7, 0.7) + } + val polymax: Int = polyX.size-1 + var step = polyX[0] + var sVal = polyY[0] + var stepT= polyX[polymax] + var sValold = polyY[polymax] + + var newVal = 1.0 + var lowVal = 1.0 + var topVal : Double + var lowX: Double + var topX: Double + var myX: Double + var lowLabl = step + + if (step > xdata) { + // extrapolate backwards + stepT = polyX[1] + sValold = polyY[1] + lowVal = sVal + topVal = sValold + lowX = step + topX = stepT + myX = xdata + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) + } else if (stepT < xdata) { + // extrapolate forwards + step = polyX[polymax-1] + sVal = polyY[polymax-1] + lowVal = sVal + topVal = sValold + lowX = step + topX = stepT + myX = xdata + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) + } else { + // interpolate + for ( i: Int in 0..polymax) { + step = polyX[i] + sVal = polyY[i] + if (step == xdata) { + newVal = sVal + break + } else if (step > xdata) { + topVal = sVal + lowX= lowLabl + myX = xdata + topX= step + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) + break + } + lowVal = sVal + lowLabl= step + } + } + if (type == "delta") {newVal = newVal * profile.delta_ISFrange_weight} // delta range + else if ( xdata>100) {newVal = newVal * profile.higher_ISFrange_weight} // higher BG range + else {newVal = newVal * profile.lower_ISFrange_weight} // lower BG range + return newVal + } + + fun withinISFlimits(liftISF: Double, minISFReduction: Double, maxISFReduction: Double, sensitivityRatio: Double, origin_sens: String, profile: OapsProfile, + high_temptarget_raises_sensitivity: Boolean, target_bg: Double, normalTarget: Int): Double { + var liftISFlimited: Double = liftISF + if ( liftISF < minISFReduction ) { + consoleError.add("weakest autoISF factor ${round(liftISF,2)} limited by autoISF_min $minISFReduction") + liftISFlimited = minISFReduction + } else if ( liftISF > maxISFReduction ) { + consoleError.add("strongest autoISF factor ${round(liftISF,2)} limited by autoISF_max $maxISFReduction") + liftISFlimited = maxISFReduction + } + var finalISF: Double + var origin_sens_final = origin_sens + if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget ) { + finalISF = liftISFlimited * sensitivityRatio + origin_sens_final = " including exercise mode impact" + } else if ( liftISFlimited >= 1 ) { + finalISF = max(liftISFlimited, sensitivityRatio) + } else { + finalISF = min(liftISFlimited, sensitivityRatio) + } + consoleError.add("final ISF factor is ${round(finalISF,2)}" + origin_sens_final) + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return finalISF + } + + fun determine_varSMBratio(profile: OapsProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double + { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target + var smb_delivery_ratio_bg_range = profile.smb_delivery_ratio_bg_range + if ( smb_delivery_ratio_bg_range<10 ) { smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 } // was in mmol/l + var fix_SMB: Double = profile.smb_delivery_ratio + var lower_SMB = min(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max) + var higher_SMB = max(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max) + var higher_bg = target_bg + smb_delivery_ratio_bg_range + var new_SMB: Double = fix_SMB + if ( smb_delivery_ratio_bg_range > 0 ) { + new_SMB = lower_SMB + (higher_SMB-lower_SMB)*(bg-target_bg) / smb_delivery_ratio_bg_range + new_SMB = max(lower_SMB, min(higher_SMB, new_SMB)) // cap if outside target_bg--higher_bg + } + if ( loop_wanted_smb=="fullLoop") { // go for max impactError.add("SMB delivery ratio set to ${max(fix_SMB, new_SMB)} as max of fixed and interpolated values") + return max(fix_SMB, new_SMB) + } + + if ( profile.smb_delivery_ratio_bg_range==0.0) { // deactivated in SMB extended menu + consoleError.add("SMB delivery ratio set to fixed value $fix_SMB") + return fix_SMB + } + if (bg <= target_bg) { + consoleError.add("SMB delivery ratio limited by minimum value $lower_SMB") + return lower_SMB + } + if (bg >= higher_bg) { + consoleError.add("SMB delivery ratio limited by maximum value $higher_SMB") + return higher_SMB + } + consoleError.add("SMB delivery ratio set to interpolated value $new_SMB") + return new_SMB + } + + fun autoISF(sens: Double, origin_sens: String, target_bg: Double, profile: OapsProfile, glucose_status: GlucoseStatus, meal_data: MealData, currentTime: Long, + sensitivityRatio: Double, loop_wanted_smb: String, high_temptarget_raises_sensitivity: Boolean, normalTarget: Int): Double { + if ( !profile.enable_autoISF) { + consoleError.add("autoISF disabled in Preferences") + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return sens + } + var dura05: Double? = glucose_status.duraISFminutes + var avg05: Double? = glucose_status.duraISFaverage + var maxISFReduction: Double = profile.autoISF_max + var sens_modified = false + var pp_ISF = 1.0 + var delta_ISF = 1.0 + var acce_ISF = 1.0 + var acce_weight: Double = 1.0 + var bg_off = target_bg+10.0 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 + + // calculate acce_ISF from bg acceleration and adapt ISF accordingly + var fit_corr: Double = glucose_status.corrSqu + var bg_acce: Double = glucose_status.bgAcceleration + if (glucose_status.a2 !=0.0 && fit_corr>=0.9) { + var minmax_delta: Double = - glucose_status.a1/2/glucose_status.a2 * 5 // back from 5min block to 1 min + var minmax_value: Double = round(glucose_status.a0 - minmax_delta*minmax_delta/25*glucose_status.a2, 1) + minmax_delta = round(minmax_delta, 1) + if (minmax_delta>0 && bg_acce<0) { + consoleError.add("Parabolic fit extrapolates a maximum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") + } else if (minmax_delta>0 && bg_acce>0.0) { + + consoleError.add("Parabolic fit extrapolates a minimum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") + if (minmax_delta<=30 && minmax_value 0 ) { + if ( bg_acce>1) { cap_weight = 0.5 } // halve the effect below target + acce_weight = profile.bgBrake_ISF_weight + } else if ( bg_acce < 0 ) { + acce_weight = profile.bgAccel_ISF_weight + } + } else if ( acce_weight==1.0) { // above target acce goes away from target + if ( bg_acce < 0.0 ) { + acce_weight = profile.bgBrake_ISF_weight + } else if ( bg_acce > 0.0 ) { + acce_weight = profile.bgAccel_ISF_weight + } + } + acce_ISF = 1.0 + bg_acce * cap_weight * acce_weight * fit_share + consoleError.add("acce_ISF adaptation is ${round(acce_ISF,2)}") + if ( acce_ISF != 1.0 ) { + sens_modified = true + } + } + + val bg_ISF = 1 + interpolate(100-bg_off, profile, "bg") + consoleError.add("bg_ISF adaptation is ${round(bg_ISF,2)}") + var liftISF = 1.0 + var final_ISF = 1.0 + if (bg_ISF<1.0) { + liftISF = min(bg_ISF, acce_ISF) + if ( acce_ISF>1.0 ) { + liftISF = bg_ISF * acce_ISF // bg_ISF could become > 1 now + consoleError.add("bg_ISF adaptation lifted to ${round(liftISF,2)} as bg accelerates already") + } + final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget) + return min(720.0, round(profile.sens / final_ISF, 1)) // observe ISF maximum of 720(?) + } else if ( bg_ISF > 1.0 ) { + sens_modified = true + } + + var bg_delta = glucose_status.delta + var deltaType: String + if (profile.enable_pp_ISF_always || profile.pp_ISF_hours >= (currentTime - meal_data.lastCarbTime) / 1000/3600) { + deltaType = "pp" + } else { + deltaType = "delta" + } + if (bg_off > 0.0) { + consoleError.add(deltaType+"_ISF adaptation by-passed as average glucose < $target_bg+10") + } else if (glucose_status.shortAvgDelta<0) { + consoleError.add(deltaType+"_ISF adaptation by-passed as no rise or too short lived") + } else if (deltaType == "pp") { + pp_ISF = 1.0 + max(0.0, bg_delta * profile.pp_ISF_weight) + consoleError.add("pp_ISF adaptation is ${round(pp_ISF,2)}") + if (pp_ISF != 1.0) { + sens_modified = true + } + + } else { + delta_ISF = interpolate(bg_delta, profile, "delta"); + // mod V14d: halve the effect below target_bg+30 + if ( bg_off > -20.0 ) { + delta_ISF = 0.5 * delta_ISF + } + delta_ISF = 1.0 + delta_ISF + consoleError.add("delta_ISF adaptation is ${round(delta_ISF,2)}") + + if (delta_ISF != 1.0) { + sens_modified = true + } + } + + var dura_ISF: Double = 1.0 + val weightISF: Double? = profile.dura_ISF_weight + if (meal_data.mealCOB>0 && !profile.enable_dura_ISF_with_COB) { + consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB,1)}") + } else if (dura05!!<10.0) { + consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05"); + } else if (avg05!! <= target_bg) { + consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") + } else { + // fight the resistance at high levels + val dura05Weight = dura05 / 60 + var avg05Weight = weightISF!! / target_bg + dura_ISF += dura05Weight*avg05Weight*(avg05-target_bg) + sens_modified = true + consoleError.add("dura_ISF adaptation is ${round(dura_ISF,2)} because ISF ${round(sens,1)} did not do it for ${round(dura05,1)}m") + } + if ( sens_modified ) { + liftISF = max(dura_ISF, max(bg_ISF, max(delta_ISF, max(acce_ISF, pp_ISF)))) + if ( acce_ISF < 1.0 ) { // 13.JAN.2022 brakes on for otherwise stronger or stable ISF + consoleError.add("strongest autoISF factor ${round(liftISF,2)} weakened to ${round(liftISF*acce_ISF,2)} as bg decelerates already") + liftISF = liftISF * acce_ISF // brakes on for otherwise stronger or stable ISF + } // brakes on for otherwise stronger or stable ISF + final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget) + return round(profile.sens / final_ISF, 1) + } + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return sens // nothing changed + } + + fun determine_basal( glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean ): RT { consoleError.clear() consoleLog.clear() + var rT = RT( algorithm = APSResult.Algorithm.SMB, runningDynamicIsf = dynIsfMode, @@ -215,40 +557,45 @@ class DetermineBasalAutoISF @Inject constructor( var min_bg = profile.min_bg var max_bg = profile.max_bg - var sensitivityRatio: Double + var sensitivityRatio: Double = 1.0 + var origin_sens = "" + var exercise_ratio = 1.0 val high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity val normalTarget = 100 // evaluate high/low temptarget against 100, not scheduled target (which might change) // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%), 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) val halfBasalTarget = profile.half_basal_exercise_target - if (dynIsfMode) { - consoleError.add("---------------------------------------------------------") - consoleError.add(" Dynamic ISF version 2.0 ") - consoleError.add("---------------------------------------------------------") - } - if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget - || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget - ) { - // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 - // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 - //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); - val c = (halfBasalTarget - normalTarget).toDouble() - sensitivityRatio = c / (c + target_bg - normalTarget) - // limit sensitivityRatio to profile.autosens_max (1.2x by default) - sensitivityRatio = min(sensitivityRatio, profile.autosens_max) - sensitivityRatio = round(sensitivityRatio, 2) - consoleLog.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") - } else { - sensitivityRatio = autosens_data.ratio - consoleLog.add("Autosens ratio: $sensitivityRatio; ") + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget) { + if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + val c = (halfBasalTarget - normalTarget).toDouble() + if (c * (c + target_bg-normalTarget) <= 0.0) { + sensitivityRatio = profile.autosens_max + } else { + sensitivityRatio = c / (c + target_bg - normalTarget) + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = min(sensitivityRatio, profile.autosens_max) + sensitivityRatio = round(sensitivityRatio, 2) + exercise_ratio = sensitivityRatio + origin_sens = "from TT modifier" + consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") + } + } else { + sensitivityRatio = autosens_data.ratio + consoleError.add("Autosens ratio: $sensitivityRatio; ") + } } + val iobTH_reduction_ratio = profile.profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; basal = profile.current_basal * sensitivityRatio basal = round_basal(basal) if (basal != profile_current_basal) - consoleLog.add("Adjusting basal from $profile_current_basal to $basal; ") + consoleError.add("Adjusting basal from $profile_current_basal to $basal; ") else - consoleLog.add("Basal unchanged: $basal; ") + consoleError.add("Basal unchanged: $basal; ") // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120 if (profile.temptargetSet) { @@ -284,21 +631,52 @@ class DetermineBasalAutoISF @Inject constructor( val minAvgDelta = min(glucose_status.shortAvgDelta, glucose_status.longAvgDelta) val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) - val sens = + var sens = if (dynIsfMode) profile.variable_sens else { val profile_sens = round(profile.sens, 1) val adjusted_sens = round(profile.sens / sensitivityRatio, 1) if (adjusted_sens != profile_sens) { - consoleLog.add("ISF from $profile_sens to $adjusted_sens") + consoleError.add("ISF from $profile_sens to $adjusted_sens") } else { - consoleLog.add("ISF unchanged: $adjusted_sens") + consoleError.add("ISF unchanged: $adjusted_sens") } adjusted_sens //console.log(" (autosens ratio "+sensitivityRatio+")"); } consoleError.add("CR:${profile.carb_ratio}") + var loop_wanted_smb: String + var enableSMB = false + if (!profile.enable_autoISF) { + loop_wanted_smb = "AAPS" + enableSMB = enable_smb( + profile, + microBolusAllowed, + meal_data, + target_bg + ) + } else { // in autoIsfMode + consoleError.add("----------------------------------") + consoleError.add("start autoISF ${profile.autoISF_version}") // fit onto narrow screens + consoleError.add("----------------------------------") + + loop_wanted_smb = loop_smb(microBolusAllowed, profile, iob_data.iob, iobTH_reduction_ratio) + if (microBolusAllowed && loop_wanted_smb != "AAPS") { + if (loop_wanted_smb == "enforced" || loop_wanted_smb == "fullLoop") { // otherwise FL switched SMB off + enableSMB = true + } + } else { + enableSMB = enable_smb( + profile, + microBolusAllowed, + meal_data, + target_bg + ) + } + sens = autoISF(sens, origin_sens, target_bg, profile, glucose_status, meal_data, currentTime, sensitivityRatio, loop_wanted_smb, high_temptarget_raises_sensitivity, normalTarget) + } + //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone val bgi = round((-iob_data.activity * sens * 5), 2) // project deviations for 30 minutes @@ -312,6 +690,7 @@ class DetermineBasalAutoISF @Inject constructor( } } + // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity val naive_eventualBG = if (dynIsfMode) @@ -358,13 +737,13 @@ class DetermineBasalAutoISF @Inject constructor( // min_bg of 90 -> threshold of 65, 100 -> 70 110 -> 75, and 130 -> 85 var threshold = min_bg - 0.5 * (min_bg - 40) - if (profile.lgsThreshold != null) { - val lgsThreshold = profile.lgsThreshold ?: error("lgsThreshold missing") - if (lgsThreshold > threshold) { - consoleError.add("Threshold set from ${convert_bg(threshold)} to ${convert_bg(lgsThreshold.toDouble())}; ") - threshold = lgsThreshold.toDouble() - } - } + // if (profile.lgsThreshold != null) { + // val lgsThreshold = profile.lgsThreshold ?: error("lgsThreshold missing") + // if (lgsThreshold > threshold) { + // consoleError.add("Threshold set from ${convert_bg(threshold)} to ${convert_bg(lgsThreshold.toDouble())}; ") + // threshold = lgsThreshold.toDouble() + // } + // } //console.error(reservoir_data); @@ -381,7 +760,7 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = sensitivityRatio, // autosens ratio (fraction of normal basal) consoleLog = consoleLog, consoleError = consoleError, - variable_sens = profile.variable_sens + variable_sens = if (dynIsfMode) profile.variable_sens else sens ) // generate predicted future BGs based on IOB, COB, and current absorption rate @@ -397,7 +776,7 @@ class DetermineBasalAutoISF @Inject constructor( ZTpredBGs.add(bg) UAMpredBGs.add(bg) - var enableSMB = enable_smb(profile, microBolusAllowed, meal_data, target_bg) + //var enableSMB = enable_smb(profile, microBolusAllowed, meal_data, target_bg) // pulled ahead for autoISF // enable UAM (if enabled in preferences) val enableUAM = profile.enableUAM @@ -659,28 +1038,6 @@ class DetermineBasalAutoISF @Inject constructor( minUAMPredBG = max(39.0, minUAMPredBG) minPredBG = round(minIOBPredBG, 0) - val fSensBG = min(minPredBG, bg) - - var future_sens: Double - if (bg > target_bg && glucose_status.delta < 3 && glucose_status.delta > -3 && glucose_status.shortAvgDelta > -3 && glucose_status.shortAvgDelta < 3 && eventualBG > target_bg && eventualBG - < bg - ) { - future_sens = (1800 / (ln((((fSensBG * 0.5) + (bg * 0.5)) / profile.insulinDivisor) + 1) * profile.TDD)) - future_sens = round(future_sens, 1) - consoleLog.add("Future state sensitivity is $future_sens based on eventual and current bg due to flat glucose level above target") - rT.reason.append("Dosing sensitivity: $future_sens using eventual BG;") - } else if (glucose_status.delta > 0 && eventualBG > target_bg || eventualBG > bg) { - future_sens = (1800 / (ln((bg / profile.insulinDivisor) + 1) * profile.TDD)) - future_sens = round(future_sens, 1) - consoleLog.add("Future state sensitivity is $future_sens using current bg due to small delta or variation") - rT.reason.append("Dosing sensitivity: $future_sens using current BG;") - } else { - future_sens = (1800 / (ln((fSensBG / profile.insulinDivisor) + 1) * profile.TDD)) - future_sens = round(future_sens, 1) - consoleLog.add("Future state sensitivity is $future_sens based on eventual bg due to -ve delta") - rT.reason.append("Dosing sensitivity: $future_sens using eventual BG;") - } - val fractionCarbsLeft = meal_data.mealCOB / meal_data.carbs // if we have COB and UAM is enabled, average both if (minUAMPredBG < 999 && minCOBPredBG < 999) { @@ -834,9 +1191,13 @@ class DetermineBasalAutoISF @Inject constructor( //rT.reason += "minGuardBG "+minGuardBG+"<"+threshold+": SMB disabled; "; enableSMB = false } - if (maxDelta > 0.20 * bg) { - consoleError.add("maxDelta ${convert_bg(maxDelta)} > 20% of BG ${convert_bg(bg)} - disabling SMB") - rT.reason.append("maxDelta " + convert_bg(maxDelta) + " > 20% of BG " + convert_bg(bg) + ": SMB disabled; ") + var maxDeltaPercentage = 0.2 // the AAPS default + if ( loop_wanted_smb=="fullLoop" ) { // only if SMB specifically requested, e.g. for full loop + maxDeltaPercentage = 0.3 + } + if ( maxDelta > maxDeltaPercentage * bg ) { + consoleError.add("maxDelta ${convert_bg(maxDelta)} > $maxDeltaPercentage% of BG ${convert_bg(bg)} - disabling SMB") + rT.reason.append("maxDelta " + convert_bg(maxDelta) + " > " + maxDeltaPercentage + "% of BG " + convert_bg(bg) + ": SMB disabled; ") enableSMB = false } @@ -910,8 +1271,8 @@ class DetermineBasalAutoISF @Inject constructor( // calculate 30m low-temp required to get projected BG up to target // multiply by 2 to low-temp faster for increased hypo safety var insulinReq = - if (dynIsfMode) 2 * min(0.0, (eventualBG - target_bg) / future_sens) - else 2 * min(0.0, (eventualBG - target_bg) / sens) + //if (dynIsfMode) 2 * min(0.0, (eventualBG - target_bg) / future_sens) + 2 * min(0.0, (eventualBG - target_bg) / sens) insulinReq = round(insulinReq, 2) // calculate naiveInsulinReq based on naive_eventualBG var naiveInsulinReq = min(0.0, (naive_eventualBG - target_bg) / sens) @@ -1018,8 +1379,8 @@ class DetermineBasalAutoISF @Inject constructor( // insulinReq is the additional insulin required to get minPredBG down to target_bg //console.error(minPredBG,eventualBG); var insulinReq = - if (dynIsfMode) round((min(minPredBG, eventualBG) - target_bg) / future_sens, 2) - else round((min(minPredBG, eventualBG) - target_bg) / sens, 2) + // if (dynIsfMode) round((min(minPredBG, eventualBG) - target_bg) / future_sens, 2) + round((min(minPredBG, eventualBG) - target_bg) / sens, 2) // if that would put us over max_iob, then reduce accordingly if (insulinReq > max_iob - iob_data.iob) { rT.reason.append("max_iob $max_iob, ") @@ -1041,17 +1402,32 @@ class DetermineBasalAutoISF @Inject constructor( if (microBolusAllowed && enableSMB && bg > threshold) { // never bolus more than maxSMBBasalMinutes worth of basal val mealInsulinReq = round(meal_data.mealCOB / profile.carb_ratio, 3) + val smb_max_range = profile.smb_max_range_extension if (iob_data.iob > mealInsulinReq && iob_data.iob > 0) { consoleError.add("IOB ${iob_data.iob} > COB ${meal_data.mealCOB}; mealInsulinReq = $mealInsulinReq") consoleError.add("profile.maxUAMSMBBasalMinutes: ${profile.maxUAMSMBBasalMinutes} profile.current_basal: ${profile.current_basal}") - maxBolus = round(profile.current_basal * profile.maxUAMSMBBasalMinutes / 60, 1) + maxBolus = round(smb_max_range * profile.current_basal * profile.maxUAMSMBBasalMinutes / 60, 1) } else { consoleError.add("profile.maxSMBBasalMinutes: ${profile.maxSMBBasalMinutes} profile.current_basal: ${profile.current_basal}") - maxBolus = round(profile.current_basal * profile.maxSMBBasalMinutes / 60, 1) + maxBolus = round(smb_max_range * profile.current_basal * profile.maxSMBBasalMinutes / 60, 1) } // bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment val roundSMBTo = 1 / profile.bolus_increment - val microBolus = Math.floor(Math.min(insulinReq / 2, maxBolus) * roundSMBTo) / roundSMBTo + //var microBolus: Double + var microBolus = Math.floor(Math.min(insulinReq / 2, maxBolus) * roundSMBTo) / roundSMBTo + //if (autoIsfMode) { + val smb_ratio = determine_varSMBratio(profile, bg.toInt(), target_bg, loop_wanted_smb) + microBolus = Math.min(insulinReq * smb_ratio, maxBolus) + // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun + val iobTHtolerance = 130 + val iobTHvirtual = profile.iob_threshold_percent * iobTHtolerance / 10000 * profile.max_iob * iobTH_reduction_ratio + if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb == "fullLoop" || loop_wanted_smb == "enforced")) { + microBolus = iobTHvirtual - iob_data.iob + consoleError.add("Full loop capped SMB at ${round(microBolus, 2)} to not exceed $iobTHtolerance% of effective iobTH ${round(iobTHvirtual / iobTHtolerance * 100, 2)}U") + } + microBolus = Math.floor(microBolus * roundSMBTo) / roundSMBTo + //} + // calculate a long enough zero temp to eventually correct back up to target val smbTarget = target_bg val worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG) / 2.0) / sens diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 2e68ed32550..c2661ec8bde 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -52,6 +52,7 @@ import app.aaps.core.objects.extensions.plannedRemainingMinutes import app.aaps.core.objects.extensions.put import app.aaps.core.objects.extensions.store import app.aaps.core.objects.extensions.target +import app.aaps.core.objects.profile.ProfileSealed import app.aaps.core.utils.MidnightUtils import app.aaps.plugins.aps.OpenAPSFragment import app.aaps.plugins.aps.R @@ -96,7 +97,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( .pluginName(R.string.openaps_auto_isf) .shortName(R.string.autoisf_shortname) .preferencesId(R.xml.pref_openapsautoisf) - .preferencesVisibleInSimpleMode(true) + .preferencesVisibleInSimpleMode(false) .showInList(config.APS) .description(R.string.description_auto_isf), aapsLogger, rh @@ -106,7 +107,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( override var lastAPSRun: Long = 0 override val algorithm = APSResult.Algorithm.SMB override var lastAPSResult: DetermineBasalResult? = null - override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) + override fun supportsDynamicIsf(): Boolean = false //preferences.get(BooleanKey.ApsUseAutoIsfWeights) override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() @@ -155,14 +156,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val dynIsfCache = LongSparseArray() private fun calculateVariableIsf(timestamp: Long, bg: Double?): Pair { // Calculate here ISF value with AutoISF algo - if (!preferences.get(BooleanKey.ApsUseAutoIsf)) return Pair("OFF", null) - + if (!preferences.get(BooleanKey.ApsUseDynamicSensitivity)) return Pair("OFF", null) val result = persistenceLayer.getApsResultCloseTo(timestamp) if (result?.variableSens != null) { //aapsLogger.debug("calculateVariableIsf $caller DB ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${result.variableSens}") return Pair("DB", result.variableSens) } - val glucose = bg ?: glucoseStatusProvider.glucoseStatusData?.glucose ?: return Pair("GLUC", null) // Round down to 30 min and use it as a key for caching // Add BG to key as it affects calculation @@ -172,7 +171,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( //aapsLogger.debug("calculateVariableIsf $caller HIT ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $cached") return Pair("HIT", cached) } - // no cached result found, let's calculate the value val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 1, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 7, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) @@ -227,13 +225,13 @@ open class OpenAPSAutoISFPlugin @Inject constructor( hardLimits.maxIC() ) ) return - if (!hardLimits.checkHardLimits(profile.getIsfMgdl("OpenAPSSMBPlugin"), app.aaps.core.ui.R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return + if (!hardLimits.checkHardLimits(profile.getIsfMgdl("OpenAPSAutoISFPlugin"), app.aaps.core.ui.R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), app.aaps.core.ui.R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return if (!hardLimits.checkHardLimits(pump.baseBasalRate, app.aaps.core.ui.R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return // End of check, start gathering data - val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) + val dynIsfMode = false // preferences.get(BooleanKey.ApsUseAutoIsf) no flag yet for AutoISF val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() @@ -262,7 +260,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } var autosensResult = AutosensResult() - val tddStatus: TddStatus? + //val tddStatus: TddStatus? var variableSensitivity = 0.0 var tdd = 0.0 if (dynIsfMode) { @@ -289,12 +287,13 @@ open class OpenAPSAutoISFPlugin @Inject constructor( ) } else { uiInteraction.dismissNotification(Notification.SMB_FALLBACK) - tddStatus = TddStatus(tdd1D, tdd7D.data.totalAmount, tddLast24H.totalAmount, tddLast4H, tddLast8to4H) - val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 - tdd = ((tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33)) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 + //tddStatus = TddStatus(tdd1D, tdd7D.data.totalAmount, tddLast24H.totalAmount, tddLast4H, tddLast8to4H) + //val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 + //tdd = ((tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33)) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 variableSensitivity = Round.roundTo(1800 / (tdd * (ln((glucoseStatus.glucose / insulinDivisor) + 1))), 0.1) - // Compare insulin consumption of last 24h with last 7 days average + // Compare insulin consumption of last 24h with last 7 days average profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 + val tddRatio = if (preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) tddLast24H.totalAmount / tdd7D.data.totalAmount else 1.0 // Because consumed carbs affects total amount of insulin compensate final ratio by consumed carbs ratio // take only 60% (expecting 40% basal). We cannot use bolus/total because of SMBs @@ -334,18 +333,18 @@ open class OpenAPSAutoISFPlugin @Inject constructor( max_bg = maxBg, target_bg = targetBg, carb_ratio = profile.getIc(), - sens = profile.getIsfMgdl("OpenAPSSMBPlugin"), + sens = profile.getIsfMgdl("OpenAPSAutoISFPlugin"), autosens_adjust_targets = false, // not used max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), - high_temptarget_raises_sensitivity = false, - low_temptarget_lowers_sensitivity = false, + high_temptarget_raises_sensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens), //was false, + low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), adv_target_adjustments = SMBDefaults.adv_target_adjustments, exercise_mode = SMBDefaults.exercise_mode, - half_basal_exercise_target = SMBDefaults.half_basal_exercise_target, + half_basal_exercise_target = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), maxCOB = SMBDefaults.maxCOB, skip_neutral_temps = pump.setNeutralTempAtFullHour(), remainingCarbsCap = SMBDefaults.remainingCarbsCap, @@ -365,9 +364,32 @@ open class OpenAPSAutoISFPlugin @Inject constructor( temptargetSet = isTempTarget, autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", - variable_sens = variableSensitivity, - insulinDivisor = insulinDivisor, - TDD = tdd + variable_sens = 47.11, //variableSensitivity, + insulinDivisor = 0, + TDD = 0.0, + autoISF_version = "3.0", // was BuildConfig.AUTOISF_VERSION) + enable_autoISF = preferences.get(BooleanKey.ApsUseAutoIsfWeights), + autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax), + autoISF_min = preferences.get(DoubleKey.ApsAutoIsfMin), + bgAccel_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight), + bgBrake_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight), + enable_pp_ISF_always = preferences.get(BooleanKey.ApsAutoIsfPpAlways), + pp_ISF_hours = preferences.get(IntKey.ApsAutoIsfPpIsfHours), + pp_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfPpWeight), + delta_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfDeltaWeight), + lower_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfLowBgWeight), + higher_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfHighBgWeight), + enable_dura_ISF_with_COB = preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs), + dura_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfDuraWeight), + smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio), + smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin), + smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax), + smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange), + smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension), + enableSMB_EvenOn_OddOff = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt), // for TT + enableSMB_EvenOn_OddOff_always = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt), // for profile target + iob_threshold_percent = preferences.get(IntKey.ApsAutoIsfIobThPercent), + profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 ) val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() @@ -465,26 +487,26 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } override fun isAutosensModeEnabled(value: Constraint): Constraint { - if (preferences.get(BooleanKey.ApsUseAutoIsf)) { - // DynISF mode - if (!preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) - value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) - } else { + // if (preferences.get(BooleanKey.ApsUseAutoIsf)) { + // // DynISF mode + // if (!preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) + // value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) + // } else { // SMB mode val enabled = preferences.get(BooleanKey.ApsUseAutosens) if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) - } + // } return value } override fun configuration(): JSONObject = JSONObject() - .put(BooleanKey.ApsUseAutoIsf, preferences, rh) + .put(BooleanKey.ApsUseDynamicSensitivity, preferences, rh) .put(IntKey.ApsDynIsfAdjustmentFactor, preferences, rh) override fun applyConfiguration(configuration: JSONObject) { configuration - .store(BooleanKey.ApsUseAutoIsf, preferences, rh) + .store(BooleanKey.ApsUseDynamicSensitivity, preferences, rh) .store(IntKey.ApsDynIsfAdjustmentFactor, preferences, rh) } } \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt index 6f9f7d18506..78b506d7ca0 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt @@ -53,6 +53,7 @@ import app.aaps.core.objects.extensions.plannedRemainingMinutes import app.aaps.core.objects.extensions.put import app.aaps.core.objects.extensions.store import app.aaps.core.objects.extensions.target +import app.aaps.core.objects.profile.ProfileSealed import app.aaps.core.utils.MidnightUtils import app.aaps.plugins.aps.OpenAPSFragment import app.aaps.plugins.aps.R @@ -368,9 +369,31 @@ open class OpenAPSSMBPlugin @Inject constructor( out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = variableSensitivity, insulinDivisor = insulinDivisor, - TDD = tdd + TDD = tdd, + autoISF_version = "", + enable_autoISF = false, + autoISF_max = 1.0, + autoISF_min = 1.0, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = false, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = false, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.0, + smb_delivery_ratio_min = 0.0, + smb_delivery_ratio_max = 0.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = false, + enableSMB_EvenOn_OddOff_always = false, + iob_threshold_percent = 100, + profile_percentage = 100 ) - val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT From 2e4771d25f0436e337121dccbf26e40e6a338592 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Thu, 15 Feb 2024 21:46:27 +0100 Subject: [PATCH 06/38] created dedicated AutoISFProfile --- .../core/interfaces/aps/AutoISFProfile.kt | 76 +++++++++++++++++++ .../aaps/core/interfaces/aps/OapsProfile.kt | 27 +------ .../core/objects/aps/DetermineBasalResult.kt | 2 + .../aps/openAPSAMA/OpenAPSAMAPlugin.kt | 25 +----- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 57 +++++++------- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 16 ++-- .../aps/openAPSSMB/OpenAPSSMBPlugin.kt | 25 +----- 7 files changed, 118 insertions(+), 110 deletions(-) create mode 100644 core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt new file mode 100644 index 00000000000..0e2f9fc1d6c --- /dev/null +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt @@ -0,0 +1,76 @@ +package app.aaps.core.interfaces.aps + +import kotlinx.serialization.Serializable + +@Serializable +data class AutoISFProfile( + var dia: Double, // AMA only + var min_5m_carbimpact: Double, // AMA only + var max_iob: Double, + var max_daily_basal: Double, + var max_basal: Double, + var min_bg: Double, + var max_bg: Double, + var target_bg: Double, + var carb_ratio: Double, + var sens: Double, + var autosens_adjust_targets: Boolean, // AMA only + var max_daily_safety_multiplier: Double, + var current_basal_safety_multiplier: Double, + var high_temptarget_raises_sensitivity: Boolean, + var low_temptarget_lowers_sensitivity: Boolean, + var sensitivity_raises_target: Boolean, + var resistance_lowers_target: Boolean, + var adv_target_adjustments: Boolean, + var exercise_mode: Boolean, + var half_basal_exercise_target: Int, + var maxCOB: Int, + var skip_neutral_temps: Boolean, + var remainingCarbsCap: Int, + var enableUAM: Boolean, + var A52_risk_enable: Boolean, + var SMBInterval: Int, + var enableSMB_with_COB: Boolean, + var enableSMB_with_temptarget: Boolean, + var allowSMB_with_high_temptarget: Boolean, + var enableSMB_always: Boolean, + var enableSMB_after_carbs: Boolean, + var maxSMBBasalMinutes: Int, + var maxUAMSMBBasalMinutes: Int, + var bolus_increment: Double, + var carbsReqThreshold: Int, + var current_basal: Double, + var temptargetSet: Boolean, + var autosens_max: Double, + var out_units: String, + var lgsThreshold: Int?, + //DynISF only + //var variable_sens: Double, + //var insulinDivisor: Int, + //var TDD: Double, + //AutoISF only + var autoISF_version: String, + var enable_autoISF: Boolean, + var autoISF_max: Double, + var autoISF_min: Double, + var bgAccel_ISF_weight: Double, + var bgBrake_ISF_weight: Double, + var enable_pp_ISF_always: Boolean, + var pp_ISF_hours: Int, + var pp_ISF_weight: Double, + var delta_ISFrange_weight: Double, + var lower_ISFrange_weight: Double, + var higher_ISFrange_weight: Double, + var enable_dura_ISF_with_COB: Boolean, + var dura_ISF_weight: Double, + var smb_delivery_ratio: Double, + var smb_delivery_ratio_min: Double, + var smb_delivery_ratio_max: Double, + var smb_delivery_ratio_bg_range: Double, + var smb_max_range_extension: Double, + var enableSMB_EvenOn_OddOff: Boolean, + var enableSMB_EvenOn_OddOff_always: Boolean, + var iob_threshold_percent: Int, + var profile_percentage: Int + +) \ No newline at end of file diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt index d2fde971768..5dbbe01c4eb 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt @@ -47,30 +47,5 @@ data class OapsProfile( //DynISF only var variable_sens: Double, var insulinDivisor: Int, - var TDD: Double, - //AutoISF only - var autoISF_version: String, - var enable_autoISF: Boolean, - var autoISF_max: Double, - var autoISF_min: Double, - var bgAccel_ISF_weight: Double, - var bgBrake_ISF_weight: Double, - var enable_pp_ISF_always: Boolean, - var pp_ISF_hours: Int, - var pp_ISF_weight: Double, - var delta_ISFrange_weight: Double, - var lower_ISFrange_weight: Double, - var higher_ISFrange_weight: Double, - var enable_dura_ISF_with_COB: Boolean, - var dura_ISF_weight: Double, - var smb_delivery_ratio: Double, - var smb_delivery_ratio_min: Double, - var smb_delivery_ratio_max: Double, - var smb_delivery_ratio_bg_range: Double, - var smb_max_range_extension: Double, - var enableSMB_EvenOn_OddOff: Boolean, - var enableSMB_EvenOn_OddOff_always: Boolean, - var iob_threshold_percent: Int, - var profile_percentage: Int - + var TDD: Double ) \ No newline at end of file diff --git a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt index 58ac79fd5af..a04b6192fe0 100644 --- a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt +++ b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt @@ -12,6 +12,7 @@ import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.constraints.Constraint @@ -79,6 +80,7 @@ class DetermineBasalResult @Inject constructor(val injector: HasAndroidInjector) override var glucoseStatus: GlucoseStatus? = null override var currentTemp: CurrentTemp? = null override var oapsProfile: OapsProfile? = null + var autoIsfProfile: AutoISFProfile? = null override var mealData: MealData? = null lateinit var result: RT diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt index 2cae5add910..c0ff0d5e551 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt @@ -214,30 +214,7 @@ class OpenAPSAMAPlugin @Inject constructor( out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = 0.0, // not used insulinDivisor = 0, // not used - TDD = 0.0, // not used - autoISF_version = "", - enable_autoISF = false, - autoISF_max = 1.0, - autoISF_min = 1.0, - bgAccel_ISF_weight = 0.0, - bgBrake_ISF_weight = 0.0, - enable_pp_ISF_always = false, - pp_ISF_hours = 3, - pp_ISF_weight = 0.0, - delta_ISFrange_weight = 0.0, - lower_ISFrange_weight = 0.0, - higher_ISFrange_weight = 0.0, - enable_dura_ISF_with_COB = false, - dura_ISF_weight = 0.0, - smb_delivery_ratio = 0.0, - smb_delivery_ratio_min = 0.0, - smb_delivery_ratio_max = 0.0, - smb_delivery_ratio_bg_range = 0.0, - smb_max_range_extension = 1.0, - enableSMB_EvenOn_OddOff = false, - enableSMB_EvenOn_OddOff_always = false, - iob_threshold_percent = 100, - profile_percentage = 100 + TDD = 0.0 // not used ) aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AMA <<<") diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index c6d32299003..102a9919000 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -1,12 +1,12 @@ package app.aaps.plugins.aps.openAPSAutoISF import app.aaps.core.interfaces.aps.APSResult +import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData -import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.profile.ProfileUtil @@ -15,7 +15,6 @@ import java.time.Instant import java.time.ZoneId import javax.inject.Inject import javax.inject.Singleton -import kotlin.math.ln import kotlin.math.max import kotlin.math.min import kotlin.math.pow @@ -60,7 +59,7 @@ class DetermineBasalAutoISF @Inject constructor( //if (profile.out_units === "mmol/L") round(value / 18, 1).toFixed(1); //else Math.round(value); - fun enable_smb(profile: OapsProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { + fun enable_smb(profile: AutoISFProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { // disable SMB when a high temptarget is set if (!microBolusAllowed) { consoleError.add("SMB disabled (!microBolusAllowed)") @@ -105,10 +104,10 @@ class DetermineBasalAutoISF @Inject constructor( consoleError.add(msg) } - private fun getMaxSafeBasal(profile: OapsProfile): Double = + private fun getMaxSafeBasal(profile: AutoISFProfile): Double = min(profile.max_basal, min(profile.max_daily_safety_multiplier * profile.max_daily_basal, profile.current_basal_safety_multiplier * profile.current_basal)) - fun setTempBasal(_rate: Double, duration: Int, profile: OapsProfile, rT: RT, currenttemp: CurrentTemp): RT { + fun setTempBasal(_rate: Double, duration: Int, profile: AutoISFProfile, rT: RT, currenttemp: CurrentTemp): RT { //var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); val maxSafeBasal = getMaxSafeBasal(profile) @@ -146,7 +145,7 @@ class DetermineBasalAutoISF @Inject constructor( } } - fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double) : String + fun loop_smb(microBolusAllowed: Boolean, profile: AutoISFProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double) : String { if ( !microBolusAllowed ) { return "AAPS" // see message in enable_smb @@ -211,7 +210,7 @@ class DetermineBasalAutoISF @Inject constructor( return "AAPS" // leave it to standard AAPS } - fun interpolate(xdata: Double, profile: OapsProfile, type: String): Double + fun interpolate(xdata: Double, profile: AutoISFProfile, type: String): Double { // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... val polyX: Array val polyY: Array @@ -284,8 +283,9 @@ class DetermineBasalAutoISF @Inject constructor( return newVal } - fun withinISFlimits(liftISF: Double, minISFReduction: Double, maxISFReduction: Double, sensitivityRatio: Double, origin_sens: String, profile: OapsProfile, - high_temptarget_raises_sensitivity: Boolean, target_bg: Double, normalTarget: Int): Double { + fun withinISFlimits( + liftISF: Double, minISFReduction: Double, maxISFReduction: Double, sensitivityRatio: Double, origin_sens: String, profile: AutoISFProfile, + high_temptarget_raises_sensitivity: Boolean, target_bg: Double, normalTarget: Int): Double { var liftISFlimited: Double = liftISF if ( liftISF < minISFReduction ) { consoleError.add("weakest autoISF factor ${round(liftISF,2)} limited by autoISF_min $minISFReduction") @@ -311,7 +311,7 @@ class DetermineBasalAutoISF @Inject constructor( return finalISF } - fun determine_varSMBratio(profile: OapsProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double + fun determine_varSMBratio(profile: AutoISFProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target var smb_delivery_ratio_bg_range = profile.smb_delivery_ratio_bg_range if ( smb_delivery_ratio_bg_range<10 ) { smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 } // was in mmol/l @@ -344,8 +344,9 @@ class DetermineBasalAutoISF @Inject constructor( return new_SMB } - fun autoISF(sens: Double, origin_sens: String, target_bg: Double, profile: OapsProfile, glucose_status: GlucoseStatus, meal_data: MealData, currentTime: Long, - sensitivityRatio: Double, loop_wanted_smb: String, high_temptarget_raises_sensitivity: Boolean, normalTarget: Int): Double { + fun autoISF( + sens: Double, origin_sens: String, target_bg: Double, profile: AutoISFProfile, glucose_status: GlucoseStatus, meal_data: MealData, currentTime: Long, + sensitivityRatio: Double, loop_wanted_smb: String, high_temptarget_raises_sensitivity: Boolean, normalTarget: Int): Double { if ( !profile.enable_autoISF) { consoleError.add("autoISF disabled in Preferences") consoleError.add("----------------------------------") @@ -488,7 +489,7 @@ class DetermineBasalAutoISF @Inject constructor( fun determine_basal( - glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, + glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: AutoISFProfile, autosens_data: AutosensResult, meal_data: MealData, microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean ): RT { consoleError.clear() @@ -631,9 +632,9 @@ class DetermineBasalAutoISF @Inject constructor( val minAvgDelta = min(glucose_status.shortAvgDelta, glucose_status.longAvgDelta) val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) - var sens = - if (dynIsfMode) profile.variable_sens - else { + //var sens = + //if (dynIsfMode) profile.variable_sens + //else { val profile_sens = round(profile.sens, 1) val adjusted_sens = round(profile.sens / sensitivityRatio, 1) if (adjusted_sens != profile_sens) { @@ -641,9 +642,9 @@ class DetermineBasalAutoISF @Inject constructor( } else { consoleError.add("ISF unchanged: $adjusted_sens") } - adjusted_sens + var sens = adjusted_sens //console.log(" (autosens ratio "+sensitivityRatio+")"); - } + //} consoleError.add("CR:${profile.carb_ratio}") var loop_wanted_smb: String @@ -760,7 +761,7 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = sensitivityRatio, // autosens ratio (fraction of normal basal) consoleLog = consoleLog, consoleError = consoleError, - variable_sens = if (dynIsfMode) profile.variable_sens else sens + variable_sens = sens // if (dynIsfMode) profile.variable_sens else sens ) // generate predicted future BGs based on IOB, COB, and current absorption rate @@ -902,16 +903,16 @@ class DetermineBasalAutoISF @Inject constructor( iobArray.forEach { iobTick -> //console.error(iobTick); val predBGI: Double = round((-iobTick.activity * sens * 5), 2) - val IOBpredBGI: Double = - if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(IOBpredBGs[IOBpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - else predBGI + val IOBpredBGI: Double = predBGI + //if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(IOBpredBGs[IOBpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + //else predBGI iobTick.iobWithZeroTemp ?: error("iobTick.iobWithZeroTemp missing") - val predZTBGI = - if (dynIsfMode) round((-iobTick.iobWithZeroTemp!!.activity * (1800 / (profile.TDD * (ln((max(ZTpredBGs[ZTpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - else round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) - val predUAMBGI = - if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(UAMpredBGs[UAMpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - else predBGI + val predZTBGI = round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) + //if (dynIsfMode) round((-iobTick.iobWithZeroTemp!!.activity * (1800 / (profile.TDD * (ln((max(ZTpredBGs[ZTpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + //else round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) + val predUAMBGI = predBGI + //if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(UAMpredBGs[UAMpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) + //else predBGI // for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero // over 60 minutes (data points every 5m) val predDev: Double = ci * (1 - min(1.0, IOBpredBGs.size / (60.0 / 5.0))) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index c2661ec8bde..e7dffa3979d 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -12,7 +12,7 @@ import app.aaps.core.interfaces.aps.APS import app.aaps.core.interfaces.aps.APSResult import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp -import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck import app.aaps.core.interfaces.configuration.Config import app.aaps.core.interfaces.constraints.Constraint @@ -323,7 +323,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() - val oapsProfile = OapsProfile( + val autoisfProfile = AutoISFProfile( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used max_iob = constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), @@ -364,9 +364,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( temptargetSet = isTempTarget, autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", - variable_sens = 47.11, //variableSensitivity, - insulinDivisor = 0, - TDD = 0.0, + //variable_sens = 47.11, //variableSensitivity, + //insulinDivisor = 0, + //TDD = 0.0, autoISF_version = "3.0", // was BuildConfig.AUTOISF_VERSION) enable_autoISF = preferences.get(BooleanKey.ApsUseAutoIsfWeights), autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax), @@ -399,7 +399,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") aapsLogger.debug(LTag.APS, "Current temp: $currentTemp") aapsLogger.debug(LTag.APS, "IOB data: ${iobArray.joinToString()}") - aapsLogger.debug(LTag.APS, "Profile: $oapsProfile") + aapsLogger.debug(LTag.APS, "Profile: $autoisfProfile") aapsLogger.debug(LTag.APS, "Autosens data: $autosensResult") aapsLogger.debug(LTag.APS, "Meal data: $mealData") aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") @@ -410,7 +410,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( glucose_status = glucoseStatus, currenttemp = currentTemp, iob_data_array = iobArray, - profile = oapsProfile, + profile = autoisfProfile, autosens_data = autosensResult, meal_data = mealData, microBolusAllowed = microBolusAllowed, @@ -425,7 +425,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( determineBasalResult.iobData = iobArray determineBasalResult.glucoseStatus = glucoseStatus determineBasalResult.currentTemp = currentTemp - determineBasalResult.oapsProfile = oapsProfile + determineBasalResult.autoIsfProfile = autoisfProfile determineBasalResult.mealData = mealData lastAPSResult = determineBasalResult lastAPSRun = now diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt index 78b506d7ca0..06f0fbd0c81 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt @@ -369,30 +369,7 @@ open class OpenAPSSMBPlugin @Inject constructor( out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = variableSensitivity, insulinDivisor = insulinDivisor, - TDD = tdd, - autoISF_version = "", - enable_autoISF = false, - autoISF_max = 1.0, - autoISF_min = 1.0, - bgAccel_ISF_weight = 0.0, - bgBrake_ISF_weight = 0.0, - enable_pp_ISF_always = false, - pp_ISF_hours = 3, - pp_ISF_weight = 0.0, - delta_ISFrange_weight = 0.0, - lower_ISFrange_weight = 0.0, - higher_ISFrange_weight = 0.0, - enable_dura_ISF_with_COB = false, - dura_ISF_weight = 0.0, - smb_delivery_ratio = 0.0, - smb_delivery_ratio_min = 0.0, - smb_delivery_ratio_max = 0.0, - smb_delivery_ratio_bg_range = 0.0, - smb_max_range_extension = 1.0, - enableSMB_EvenOn_OddOff = false, - enableSMB_EvenOn_OddOff_always = false, - iob_threshold_percent = 100, - profile_percentage = 100 + TDD = tdd ) val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT From 01db3f199122b1e0a8f085d64c4f697cbb22860f Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Fri, 16 Feb 2024 01:44:48 +0100 Subject: [PATCH 07/38] kt verification test data for AutoISF --- .../assets/results/2023-12-23_030034.json | 3 + .../assets/results/2023-12-23_030536.json | 3 + .../assets/results/2023-12-23_031036.json | 3 + .../assets/results/2023-12-23_031536.json | 3 + .../assets/results/2023-12-23_032036.json | 3 + .../assets/results/2023-12-23_032535.json | 3 + .../assets/results/2023-12-23_033036.json | 3 + .../assets/results/2023-12-23_033541.json | 952 ++++++++++++++++++ .../assets/results/2024-01-05_110247.json | 4 + .../assets/results/2024-01-05_110747.json | 3 + .../assets/results/2024-01-05_111248.json | 3 + .../assets/results/2024-01-05_111747.json | 3 + .../assets/results/2024-01-05_112247.json | 3 + .../assets/results/2024-01-05_112745.json | 3 + .../assets/results/2024-01-05_113245.json | 3 + .../assets/results/2024-01-05_113747.json | 3 + .../assets/results/2024-01-05_114246.json | 3 + .../assets/results/2024-01-05_114747.json | 3 + .../assets/results/2024-01-05_115511.json | 3 + .../assets/results/2024-01-05_115754.json | 3 + .../assets/results/2024-01-06_174057.json | 1 + .../assets/results/2024-01-06_174548.json | 1 + 22 files changed, 1012 insertions(+) create mode 100644 app/src/androidTest/assets/results/2023-12-23_030034.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_030536.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_031036.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_031536.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_032036.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_032535.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_033036.json create mode 100644 app/src/androidTest/assets/results/2023-12-23_033541.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_110247.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_110747.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_111248.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_111747.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_112247.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_112745.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_113245.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_113747.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_114246.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_114747.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_115511.json create mode 100644 app/src/androidTest/assets/results/2024-01-05_115754.json create mode 100644 app/src/androidTest/assets/results/2024-01-06_174057.json create mode 100644 app/src/androidTest/assets/results/2024-01-06_174548.json diff --git a/app/src/androidTest/assets/results/2023-12-23_030034.json b/app/src/androidTest/assets/results/2023-12-23_030034.json new file mode 100644 index 00000000000..3add28113d6 --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_030034.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":121,"noise":0,"delta":-18.44,"short_avgdelta":-18.44,"long_avgdelta":-11.97,"date":1703296800000,"dura_ISF_minutes":0,"dura_ISF_average":121,"parabola_fit_correlation":0.995,"parabola_fit_minutes":15,"parabola_fit_last_delta":-18.800000000000008,"parabola_fit_next_delta":-17.799999999999958,"parabola_fit_a0":120.3,"parabola_fit_a1":-18.3,"parabola_fit_a2":0.5,"bg_acceleration":1.0000000000000497},"currenttemp":{"temp":"absolute","duration":110,"rate":0,"minutesrunning":10},"iob_data":[{"iob":0.512,"basaliob":0.512,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:00:33.368Z","iobWithZeroTemp":{"iob":0.512,"basaliob":0.512,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:00:33.368Z"}},{"iob":0.488,"basaliob":0.488,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:05:33.368Z","iobWithZeroTemp":{"iob":0.471,"basaliob":0.471,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:05:33.368Z"}},{"iob":0.465,"basaliob":0.465,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:10:33.368Z","iobWithZeroTemp":{"iob":0.428,"basaliob":0.428,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:10:33.368Z"}},{"iob":0.441,"basaliob":0.441,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:15:33.368Z","iobWithZeroTemp":{"iob":0.383,"basaliob":0.383,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:33.368Z"}},{"iob":0.417,"basaliob":0.417,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:20:33.368Z","iobWithZeroTemp":{"iob":0.339,"basaliob":0.339,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:33.368Z"}},{"iob":0.395,"basaliob":0.395,"bolussnooze":0,"activity":0.0045,"lastBolusTime":0,"time":"2023-12-23T02:25:33.368Z","iobWithZeroTemp":{"iob":0.298,"basaliob":0.298,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:33.368Z"}},{"iob":0.372,"basaliob":0.372,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:30:33.368Z","iobWithZeroTemp":{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:33.368Z"}},{"iob":0.351,"basaliob":0.351,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2023-12-23T02:35:33.368Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:33.368Z"}},{"iob":0.33,"basaliob":0.33,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2023-12-23T02:40:33.368Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:33.368Z"}},{"iob":0.31,"basaliob":0.31,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2023-12-23T02:45:33.368Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:33.368Z"}},{"iob":0.29,"basaliob":0.29,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2023-12-23T02:50:33.368Z","iobWithZeroTemp":{"iob":0.104,"basaliob":0.104,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:33.368Z"}},{"iob":0.272,"basaliob":0.272,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2023-12-23T02:55:33.368Z","iobWithZeroTemp":{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:33.368Z"}},{"iob":0.254,"basaliob":0.254,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2023-12-23T03:00:33.368Z","iobWithZeroTemp":{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:33.368Z"}},{"iob":0.237,"basaliob":0.237,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2023-12-23T03:05:33.368Z","iobWithZeroTemp":{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:05:33.368Z"}},{"iob":0.221,"basaliob":0.221,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T03:10:33.368Z","iobWithZeroTemp":{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:10:33.368Z"}},{"iob":0.206,"basaliob":0.206,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T03:15:33.368Z","iobWithZeroTemp":{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:33.368Z"}},{"iob":0.192,"basaliob":0.192,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T03:20:33.368Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T03:20:33.368Z"}},{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2023-12-23T03:25:33.368Z","iobWithZeroTemp":{"iob":-0.066,"basaliob":-0.066,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:33.368Z"}},{"iob":0.165,"basaliob":0.165,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T03:30:33.368Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:33.368Z"}},{"iob":0.153,"basaliob":0.153,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2023-12-23T03:35:33.368Z","iobWithZeroTemp":{"iob":-0.098,"basaliob":-0.098,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:33.368Z"}},{"iob":0.142,"basaliob":0.142,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:40:33.368Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:33.368Z"}},{"iob":0.131,"basaliob":0.131,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:45:33.368Z","iobWithZeroTemp":{"iob":-0.126,"basaliob":-0.126,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:33.368Z"}},{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:50:33.368Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:33.368Z"}},{"iob":0.112,"basaliob":0.112,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:55:33.368Z","iobWithZeroTemp":{"iob":-0.149,"basaliob":-0.149,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:33.368Z"}},{"iob":0.103,"basaliob":0.103,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T04:00:33.368Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:33.368Z"}},{"iob":0.095,"basaliob":0.095,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T04:05:33.368Z","iobWithZeroTemp":{"iob":-0.17,"basaliob":-0.17,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:33.368Z"}},{"iob":0.087,"basaliob":0.087,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T04:10:33.368Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:33.368Z"}},{"iob":0.08,"basaliob":0.08,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T04:15:33.368Z","iobWithZeroTemp":{"iob":-0.188,"basaliob":-0.188,"bolussnooze":0,"activity":-0.001,"lastBolusTime":0,"time":"2023-12-23T04:15:33.368Z"}},{"iob":0.074,"basaliob":0.074,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T04:20:33.368Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:33.368Z"}},{"iob":0.068,"basaliob":0.068,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T04:25:33.368Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:33.368Z"}},{"iob":0.062,"basaliob":0.062,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:30:33.368Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:33.368Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:35:33.368Z","iobWithZeroTemp":{"iob":-0.214,"basaliob":-0.214,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:33.368Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:33.368Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:40:33.368Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:33.368Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:33.368Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:33.368Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:50:33.368Z"}},{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:33.368Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T04:55:33.368Z"}},{"iob":0.035,"basaliob":0.035,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:33.368Z","iobWithZeroTemp":{"iob":-0.239,"basaliob":-0.239,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T05:00:33.368Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:33.368Z","iobWithZeroTemp":{"iob":-0.242,"basaliob":-0.242,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:33.368Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:33.368Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:10:33.368Z"}},{"iob":0.026,"basaliob":0.026,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:33.368Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:33.368Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:33.368Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:20:33.368Z"}},{"iob":0.021,"basaliob":0.021,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:33.368Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:25:33.368Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:33.368Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:30:33.368Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:33.368Z","iobWithZeroTemp":{"iob":-0.258,"basaliob":-0.258,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:33.368Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:33.368Z","iobWithZeroTemp":{"iob":-0.26,"basaliob":-0.26,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:40:33.368Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:33.368Z","iobWithZeroTemp":{"iob":-0.26,"basaliob":-0.26,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:45:33.368Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:33.368Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:33.368Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:33.368Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:55:33.368Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units": "mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-3.6007999999999996,"slopeFromMinDeviation":0,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703296834618,"flatBGsDetected":false},"output":{"temp":"absolute","bg":121,"tick":-18,"eventualBG":6,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:00:34.618Z","sensitivityRatio":1,"predBGs":{"IOB":[121,104,88,74,60,49,39,39,39,39,39,39,39],"ZT":[121,118,115,113,110,107,105,103,100,98,97,95,94,92,91,90,90,89,89,88,88,88,88,88,88,89,89,90,90,91]},"COB":0,"IOB":0.512,"reason":"COB: 0, Dev: -55, BGI: -3, ISF: 117, CR: 18.5, Target: 91, minPredBG 42, minGuardBG -25, IOBpredBG 39; minGuardBG -25<66","duration":120,"rate":0,"timestamp":"2023-12-23T02:00:34.627Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_030536.json b/app/src/androidTest/assets/results/2023-12-23_030536.json new file mode 100644 index 00000000000..2303cf1587c --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_030536.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":119,"noise":0,"delta":-8.33,"short_avgdelta":-8.33,"long_avgdelta":-12.05,"date":1703297100000,"dura_ISF_minutes":5,"dura_ISF_average":120,"parabola_fit_correlation":0.9984,"parabola_fit_minutes":15,"parabola_fit_last_delta":-3.1999999999997897,"parabola_fit_next_delta":7.8000000000000815,"parabola_fit_a0":118.7,"parabola_fit_a1":2.3,"parabola_fit_a2":5.5,"bg_acceleration":10.999999999999872},"currenttemp":{"temp":"absolute","duration":105,"rate":0,"minutesrunning":15},"iob_data":[{"iob":0.468,"basaliob":0.468,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:05:34.566Z","iobWithZeroTemp":{"iob":0.468,"basaliob":0.468,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2023-12-23T02:05:34.566Z"}},{"iob":0.444,"basaliob":0.444,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:10:34.566Z","iobWithZeroTemp":{"iob":0.427,"basaliob":0.427,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:10:34.566Z"}},{"iob":0.42,"basaliob":0.42,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:34.566Z","iobWithZeroTemp":{"iob":0.383,"basaliob":0.383,"bolussnooze":0,"activity":0.0045,"lastBolusTime":0,"time":"2023-12-23T02:15:34.566Z"}},{"iob":0.397,"basaliob":0.397,"bolussnooze":0,"activity":0.0045,"lastBolusTime":0,"time":"2023-12-23T02:20:34.566Z","iobWithZeroTemp":{"iob":0.339,"basaliob":0.339,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.566Z"}},{"iob":0.375,"basaliob":0.375,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:25:34.566Z","iobWithZeroTemp":{"iob":0.297,"basaliob":0.297,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.566Z"}},{"iob":0.353,"basaliob":0.353,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2023-12-23T02:30:34.566Z","iobWithZeroTemp":{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.566Z"}},{"iob":0.332,"basaliob":0.332,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2023-12-23T02:35:34.566Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:34.566Z"}},{"iob":0.312,"basaliob":0.312,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:40:34.566Z","iobWithZeroTemp":{"iob":0.177,"basaliob":0.177,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:34.566Z"}},{"iob":0.293,"basaliob":0.293,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2023-12-23T02:45:34.566Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:34.566Z"}},{"iob":0.274,"basaliob":0.274,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2023-12-23T02:50:34.566Z","iobWithZeroTemp":{"iob":0.105,"basaliob":0.105,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:34.566Z"}},{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2023-12-23T02:55:34.566Z","iobWithZeroTemp":{"iob":0.07,"basaliob":0.07,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:34.566Z"}},{"iob":0.239,"basaliob":0.239,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2023-12-23T03:00:34.566Z","iobWithZeroTemp":{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:34.566Z"}},{"iob":0.223,"basaliob":0.223,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T03:05:34.566Z","iobWithZeroTemp":{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:05:34.566Z"}},{"iob":0.208,"basaliob":0.208,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T03:10:34.566Z","iobWithZeroTemp":{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:10:34.566Z"}},{"iob":0.193,"basaliob":0.193,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T03:15:34.566Z","iobWithZeroTemp":{"iob":-0.029,"basaliob":-0.029,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:34.566Z"}},{"iob":0.18,"basaliob":0.18,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2023-12-23T03:20:34.566Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T03:20:34.566Z"}},{"iob":0.167,"basaliob":0.167,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T03:25:34.566Z","iobWithZeroTemp":{"iob":-0.065,"basaliob":-0.065,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:34.566Z"}},{"iob":0.155,"basaliob":0.155,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:30:34.566Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:34.566Z"}},{"iob":0.143,"basaliob":0.143,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:35:34.566Z","iobWithZeroTemp":{"iob":-0.098,"basaliob":-0.098,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:34.566Z"}},{"iob":0.133,"basaliob":0.133,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:40:34.566Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:34.566Z"}},{"iob":0.122,"basaliob":0.122,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:45:34.566Z","iobWithZeroTemp":{"iob":-0.126,"basaliob":-0.126,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:34.566Z"}},{"iob":0.113,"basaliob":0.113,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:50:34.566Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:34.566Z"}},{"iob":0.104,"basaliob":0.104,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:55:34.566Z","iobWithZeroTemp":{"iob":-0.15,"basaliob":-0.15,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:34.566Z"}},{"iob":0.096,"basaliob":0.096,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T04:00:34.566Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:34.566Z"}},{"iob":0.088,"basaliob":0.088,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T04:05:34.566Z","iobWithZeroTemp":{"iob":-0.17,"basaliob":-0.17,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:34.566Z"}},{"iob":0.081,"basaliob":0.081,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T04:10:34.566Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:34.566Z"}},{"iob":0.074,"basaliob":0.074,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T04:15:34.566Z","iobWithZeroTemp":{"iob":-0.188,"basaliob":-0.188,"bolussnooze":0,"activity":-0.001,"lastBolusTime":0,"time":"2023-12-23T04:15:34.566Z"}},{"iob":0.068,"basaliob":0.068,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.566Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.566Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:25:34.566Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:34.566Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:30:34.566Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:34.566Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:35:34.566Z","iobWithZeroTemp":{"iob":-0.215,"basaliob":-0.215,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:34.566Z"}},{"iob":0.048,"basaliob":0.048,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:34.566Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:40:34.566Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:34.566Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:34.566Z"}},{"iob":0.04,"basaliob":0.04,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:34.566Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:50:34.566Z"}},{"iob":0.036,"basaliob":0.036,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:34.566Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T04:55:34.566Z"}},{"iob":0.033,"basaliob":0.033,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:34.566Z","iobWithZeroTemp":{"iob":-0.238,"basaliob":-0.238,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:00:34.566Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:34.566Z","iobWithZeroTemp":{"iob":-0.242,"basaliob":-0.242,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:34.566Z"}},{"iob":0.027,"basaliob":0.027,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:34.566Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:10:34.566Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:34.566Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:34.566Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:34.566Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:20:34.566Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:34.566Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:34.566Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:34.566Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:30:34.566Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:34.566Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:34.566Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:34.566Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:40:34.566Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:34.566Z","iobWithZeroTemp":{"iob":-0.26,"basaliob":-0.26,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:45:34.566Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:34.566Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:34.566Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:34.566Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T05:55:34.566Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:34.566Z","iobWithZeroTemp":{"iob":-0.264,"basaliob":-0.264,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:00:34.566Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units": "mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-2.788636363636363,"slopeFromMinDeviation":5.333000000000001,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703297135979,"flatBGsDetected":false},"output":{"temp":"absolute","bg":119,"tick":-8,"eventualBG":34,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:05:35.979Z","sensitivityRatio":1,"predBGs":{"IOB":[119,111,104,98,92,87,82,79,75,73,71,70,69,68,68,67,67,66,66,66,65,65,64,64,64,64,63,63,63,63,62,62,62,62,62,62,62,61],"ZT":[119,118,117,116,116,115,114,113,113,112,112,111,111,110,110,110,110,109,109,109,109,109,109,109,110,110,110,110,110,111,111,111,111,112,112,112,113,113,114,114,114,115,115,116,116,116,117,117]},"COB":0,"IOB":0.468,"reason":"COB: 0, Dev: -67, BGI: -1, ISF: 38, CR: 18.5, Target: 91, minPredBG 85, minGuardBG 61, IOBpredBG 61; minGuardBG 61<66","duration":120,"rate":0,"timestamp":"2023-12-23T02:05:35.988Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_031036.json b/app/src/androidTest/assets/results/2023-12-23_031036.json new file mode 100644 index 00000000000..838a6da299b --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_031036.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":101,"noise":0,"delta":-13.33,"short_avgdelta":-13.33,"long_avgdelta":-13.9,"date":1703297400000,"dura_ISF_minutes":0,"dura_ISF_average":101,"parabola_fit_correlation":0.9815,"parabola_fit_minutes":25,"parabola_fit_last_delta":-8.91428571428596,"parabola_fit_next_delta":-5.771428571428798,"parabola_fit_a0":103.6,"parabola_fit_a1":-7.34,"parabola_fit_a2":1.57,"bg_acceleration":3.142857142857161},"currenttemp":{"temp":"absolute","duration":100,"rate":0,"minutesrunning":20},"iob_data":[{"iob":0.423,"basaliob":0.423,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:10:34.518Z","iobWithZeroTemp":{"iob":0.423,"basaliob":0.423,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2023-12-23T02:10:34.518Z"}},{"iob":0.4,"basaliob":0.4,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:34.518Z","iobWithZeroTemp":{"iob":0.383,"basaliob":0.383,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:34.518Z"}},{"iob":0.377,"basaliob":0.377,"bolussnooze":0,"activity":0.0045,"lastBolusTime":0,"time":"2023-12-23T02:20:34.518Z","iobWithZeroTemp":{"iob":0.34,"basaliob":0.34,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.518Z"}},{"iob":0.355,"basaliob":0.355,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2023-12-23T02:25:34.518Z","iobWithZeroTemp":{"iob":0.297,"basaliob":0.297,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.518Z"}},{"iob":0.334,"basaliob":0.334,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:30:34.518Z","iobWithZeroTemp":{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.518Z"}},{"iob":0.313,"basaliob":0.313,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:35:34.518Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:34.518Z"}},{"iob":0.294,"basaliob":0.294,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2023-12-23T02:40:34.518Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:34.518Z"}},{"iob":0.275,"basaliob":0.275,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:45:34.518Z","iobWithZeroTemp":{"iob":0.14,"basaliob":0.14,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:34.518Z"}},{"iob":0.257,"basaliob":0.257,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2023-12-23T02:50:34.518Z","iobWithZeroTemp":{"iob":0.105,"basaliob":0.105,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:34.518Z"}},{"iob":0.24,"basaliob":0.24,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2023-12-23T02:55:34.518Z","iobWithZeroTemp":{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:34.518Z"}},{"iob":0.224,"basaliob":0.224,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2023-12-23T03:00:34.518Z","iobWithZeroTemp":{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:34.518Z"}},{"iob":0.209,"basaliob":0.209,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T03:05:34.518Z","iobWithZeroTemp":{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:05:34.518Z"}},{"iob":0.194,"basaliob":0.194,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T03:10:34.518Z","iobWithZeroTemp":{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T03:10:34.518Z"}},{"iob":0.18,"basaliob":0.18,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2023-12-23T03:15:34.518Z","iobWithZeroTemp":{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:34.518Z"}},{"iob":0.167,"basaliob":0.167,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T03:20:34.518Z","iobWithZeroTemp":{"iob":-0.048,"basaliob":-0.048,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T03:20:34.518Z"}},{"iob":0.155,"basaliob":0.155,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:25:34.518Z","iobWithZeroTemp":{"iob":-0.065,"basaliob":-0.065,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:34.518Z"}},{"iob":0.144,"basaliob":0.144,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:30:34.518Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:34.518Z"}},{"iob":0.133,"basaliob":0.133,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:35:34.518Z","iobWithZeroTemp":{"iob":-0.097,"basaliob":-0.097,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:34.518Z"}},{"iob":0.123,"basaliob":0.123,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2023-12-23T03:40:34.518Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:34.518Z"}},{"iob":0.113,"basaliob":0.113,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:45:34.518Z","iobWithZeroTemp":{"iob":-0.126,"basaliob":-0.126,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:34.518Z"}},{"iob":0.104,"basaliob":0.104,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:50:34.518Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:34.518Z"}},{"iob":0.096,"basaliob":0.096,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:55:34.518Z","iobWithZeroTemp":{"iob":-0.15,"basaliob":-0.15,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:34.518Z"}},{"iob":0.088,"basaliob":0.088,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T04:00:34.518Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:34.518Z"}},{"iob":0.081,"basaliob":0.081,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T04:05:34.518Z","iobWithZeroTemp":{"iob":-0.17,"basaliob":-0.17,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:34.518Z"}},{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T04:10:34.518Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:34.518Z"}},{"iob":0.068,"basaliob":0.068,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T04:15:34.518Z","iobWithZeroTemp":{"iob":-0.188,"basaliob":-0.188,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2023-12-23T04:15:34.518Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:20:34.518Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.518Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:25:34.518Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:34.518Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:30:34.518Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:34.518Z"}},{"iob":0.048,"basaliob":0.048,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:35:34.518Z","iobWithZeroTemp":{"iob":-0.215,"basaliob":-0.215,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:34.518Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:34.518Z","iobWithZeroTemp":{"iob":-0.221,"basaliob":-0.221,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:40:34.518Z"}},{"iob":0.04,"basaliob":0.04,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:34.518Z","iobWithZeroTemp":{"iob":-0.225,"basaliob":-0.225,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:34.518Z"}},{"iob":0.036,"basaliob":0.036,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:34.518Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:50:34.518Z"}},{"iob":0.033,"basaliob":0.033,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:34.518Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T04:55:34.518Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:34.518Z","iobWithZeroTemp":{"iob":-0.239,"basaliob":-0.239,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T05:00:34.518Z"}},{"iob":0.027,"basaliob":0.027,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:34.518Z","iobWithZeroTemp":{"iob":-0.241,"basaliob":-0.241,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:34.518Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:34.518Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:10:34.518Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:34.518Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:34.518Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:34.518Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:20:34.518Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:34.518Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:34.518Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:34.518Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:30:34.518Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:34.518Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:34.518Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:34.518Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:40:34.518Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:34.518Z","iobWithZeroTemp":{"iob":-0.261,"basaliob":-0.261,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:45:34.518Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:34.518Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:34.518Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:34.518Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:55:34.518Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:34.518Z","iobWithZeroTemp":{"iob":-0.264,"basaliob":-0.264,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T06:00:34.518Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:05:34.518Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T06:05:34.518Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units": "mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-2.233363636363636,"slopeFromMinDeviation":3.6290000000000004,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703297435868,"flatBGsDetected":false},"output":{"temp":"absolute","bg":101,"tick":-13,"eventualBG":-6,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:10:35.868Z","sensitivityRatio":1,"predBGs":{"IOB":[101,89,77,67,58,49,42,39,39,39,39,39,39],"ZT":[101,99,97,95,93,92,90,89,87,86,85,84,83,83,82,82,81,81,81,81,81,81,81,82,82,82,83,83,84,85,85,86,87,87,88,89,90,91,92,92]},"COB":0,"IOB":0.423,"reason":"COB: 0, Dev: -71, BGI: -2, ISF: 85, CR: 18.5, Target: 91, minPredBG 47, minGuardBG 3, IOBpredBG 39; minGuardBG 3<66","duration":120,"rate":0,"timestamp":"2023-12-23T02:10:35.878Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_031536.json b/app/src/androidTest/assets/results/2023-12-23_031536.json new file mode 100644 index 00000000000..9b4075678ba --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_031536.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":94,"noise":0,"delta":-9.5,"short_avgdelta":-9.5,"long_avgdelta":-12.72,"date":1703297700000,"dura_ISF_minutes":0,"dura_ISF_average":94,"parabola_fit_correlation":0.9858,"parabola_fit_minutes":30,"parabola_fit_last_delta":-7.309523809524034,"parabola_fit_next_delta":-4.619047619047871,"parabola_fit_a0":94.9,"parabola_fit_a1":-5.96,"parabola_fit_a2":1.35,"bg_acceleration":2.690476190476163},"currenttemp":{"temp":"absolute","duration":95,"rate":0,"minutesrunning":25},"iob_data":[{"iob":0.379,"basaliob":0.379,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:34.622Z","iobWithZeroTemp":{"iob":0.379,"basaliob":0.379,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2023-12-23T02:15:34.622Z"}},{"iob":0.356,"basaliob":0.356,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.622Z","iobWithZeroTemp":{"iob":0.339,"basaliob":0.339,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.622Z"}},{"iob":0.335,"basaliob":0.335,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.622Z","iobWithZeroTemp":{"iob":0.298,"basaliob":0.298,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2023-12-23T02:25:34.622Z"}},{"iob":0.314,"basaliob":0.314,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2023-12-23T02:30:34.622Z","iobWithZeroTemp":{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.622Z"}},{"iob":0.294,"basaliob":0.294,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2023-12-23T02:35:34.622Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:34.622Z"}},{"iob":0.275,"basaliob":0.275,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:40:34.622Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:34.622Z"}},{"iob":0.257,"basaliob":0.257,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2023-12-23T02:45:34.622Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:34.622Z"}},{"iob":0.24,"basaliob":0.24,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:50:34.622Z","iobWithZeroTemp":{"iob":0.105,"basaliob":0.105,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:34.622Z"}},{"iob":0.223,"basaliob":0.223,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2023-12-23T02:55:34.622Z","iobWithZeroTemp":{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:34.622Z"}},{"iob":0.208,"basaliob":0.208,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T03:00:34.622Z","iobWithZeroTemp":{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:34.622Z"}},{"iob":0.193,"basaliob":0.193,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T03:05:34.622Z","iobWithZeroTemp":{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:05:34.622Z"}},{"iob":0.179,"basaliob":0.179,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2023-12-23T03:10:34.622Z","iobWithZeroTemp":{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:10:34.622Z"}},{"iob":0.166,"basaliob":0.166,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T03:15:34.622Z","iobWithZeroTemp":{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:34.622Z"}},{"iob":0.154,"basaliob":0.154,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:20:34.622Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T03:20:34.622Z"}},{"iob":0.142,"basaliob":0.142,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:25:34.622Z","iobWithZeroTemp":{"iob":-0.066,"basaliob":-0.066,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:34.622Z"}},{"iob":0.132,"basaliob":0.132,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:30:34.622Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:34.622Z"}},{"iob":0.122,"basaliob":0.122,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2023-12-23T03:35:34.622Z","iobWithZeroTemp":{"iob":-0.097,"basaliob":-0.097,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:34.622Z"}},{"iob":0.112,"basaliob":0.112,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:40:34.622Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:34.622Z"}},{"iob":0.103,"basaliob":0.103,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:45:34.622Z","iobWithZeroTemp":{"iob":-0.126,"basaliob":-0.126,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:34.622Z"}},{"iob":0.095,"basaliob":0.095,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:50:34.622Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:34.622Z"}},{"iob":0.087,"basaliob":0.087,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T03:55:34.622Z","iobWithZeroTemp":{"iob":-0.15,"basaliob":-0.15,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:34.622Z"}},{"iob":0.08,"basaliob":0.08,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T04:00:34.622Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:34.622Z"}},{"iob":0.074,"basaliob":0.074,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T04:05:34.622Z","iobWithZeroTemp":{"iob":-0.169,"basaliob":-0.169,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:34.622Z"}},{"iob":0.067,"basaliob":0.067,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T04:10:34.622Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:34.622Z"}},{"iob":0.062,"basaliob":0.062,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:15:34.622Z","iobWithZeroTemp":{"iob":-0.187,"basaliob":-0.187,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2023-12-23T04:15:34.622Z"}},{"iob":0.056,"basaliob":0.056,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:20:34.622Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.622Z"}},{"iob":0.051,"basaliob":0.051,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:25:34.622Z","iobWithZeroTemp":{"iob":-0.203,"basaliob":-0.203,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:34.622Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:30:34.622Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:34.622Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:35:34.622Z","iobWithZeroTemp":{"iob":-0.215,"basaliob":-0.215,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:34.622Z"}},{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:34.622Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:40:34.622Z"}},{"iob":0.035,"basaliob":0.035,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:34.622Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:34.622Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:34.622Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:50:34.622Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:34.622Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:55:34.622Z"}},{"iob":0.026,"basaliob":0.026,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:34.622Z","iobWithZeroTemp":{"iob":-0.238,"basaliob":-0.238,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:00:34.622Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:34.622Z","iobWithZeroTemp":{"iob":-0.241,"basaliob":-0.241,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:34.622Z"}},{"iob":0.021,"basaliob":0.021,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:34.622Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:10:34.622Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:34.622Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:34.622Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:34.622Z","iobWithZeroTemp":{"iob":-0.251,"basaliob":-0.251,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:20:34.622Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:34.622Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:34.622Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:34.622Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:30:34.622Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:34.622Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:34.622Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:34.622Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:40:34.622Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:34.622Z","iobWithZeroTemp":{"iob":-0.26,"basaliob":-0.26,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:45:34.622Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:34.622Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:34.622Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:34.622Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:55:34.622Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:34.622Z","iobWithZeroTemp":{"iob":-0.264,"basaliob":-0.264,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T06:00:34.622Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:05:34.622Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T06:05:34.622Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:10:34.622Z","iobWithZeroTemp":{"iob":-0.267,"basaliob":-0.267,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:10:34.622Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7,"autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4, + "out_units": "mg\/dL", + "bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-1.6613636363636364,"slopeFromMinDeviation":3.394333333333333,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703297736430,"flatBGsDetected":false},"output":{"temp":"absolute","bg":94,"tick":-9,"eventualBG":-40,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:15:36.430Z","sensitivityRatio":1,"predBGs":{"IOB":[94,85,76,68,61,54,47,42,39,39,39,39,39],"ZT":[94,89,83,78,74,69,65,62,58,55,53,50,49,47,46,45,44,44,43,44,44,44,45,46,47,48,50,51,53,55,57,59,61,63,66,68,70,73,75,78,81,83,86,89]},"COB":0,"IOB":0.379,"reason":"COB: 0, Dev: -44, BGI: -5, ISF: 238, CR: 18.5, Target: 91, minPredBG 41, minGuardBG -20, IOBpredBG 39; 5 add'l carbs req w\/in 20m; minGuardBG -20<66","carbsReq":5,"carbsReqWithin":20,"duration":120,"rate":0,"timestamp":"2023-12-23T02:15:36.439Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_032036.json b/app/src/androidTest/assets/results/2023-12-23_032036.json new file mode 100644 index 00000000000..ed38eec5263 --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_032036.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":90,"noise":0,"delta":-6.39,"short_avgdelta":-6.39,"long_avgdelta":-10.74,"date":1703298000000,"dura_ISF_minutes":5,"dura_ISF_average":92,"parabola_fit_correlation":0.9935,"parabola_fit_minutes":15,"parabola_fit_last_delta":-2.4000000000001265,"parabola_fit_next_delta":4.599999999999973,"parabola_fit_a0":90.4,"parabola_fit_a1":1.1,"parabola_fit_a2":3.5,"bg_acceleration":7.0000000000000995},"currenttemp":{"temp":"absolute","duration":90,"rate":0,"minutesrunning":30},"iob_data":[{"iob":0.336,"basaliob":0.336,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.728Z","iobWithZeroTemp":{"iob":0.336,"basaliob":0.336,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2023-12-23T02:20:34.728Z"}},{"iob":0.314,"basaliob":0.314,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.728Z","iobWithZeroTemp":{"iob":0.297,"basaliob":0.297,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.728Z"}},{"iob":0.294,"basaliob":0.294,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.728Z","iobWithZeroTemp":{"iob":0.257,"basaliob":0.257,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2023-12-23T02:30:34.728Z"}},{"iob":0.274,"basaliob":0.274,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2023-12-23T02:35:34.728Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:34.728Z"}},{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2023-12-23T02:40:34.728Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:34.728Z"}},{"iob":0.238,"basaliob":0.238,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:45:34.728Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:34.728Z"}},{"iob":0.221,"basaliob":0.221,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2023-12-23T02:50:34.728Z","iobWithZeroTemp":{"iob":0.105,"basaliob":0.105,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:34.728Z"}},{"iob":0.206,"basaliob":0.206,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T02:55:34.728Z","iobWithZeroTemp":{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T02:55:34.728Z"}},{"iob":0.191,"basaliob":0.191,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2023-12-23T03:00:34.728Z","iobWithZeroTemp":{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:34.728Z"}},{"iob":0.177,"basaliob":0.177,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2023-12-23T03:05:34.728Z","iobWithZeroTemp":{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:05:34.728Z"}},{"iob":0.164,"basaliob":0.164,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T03:10:34.728Z","iobWithZeroTemp":{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T03:10:34.728Z"}},{"iob":0.152,"basaliob":0.152,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:15:34.728Z","iobWithZeroTemp":{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:34.728Z"}},{"iob":0.14,"basaliob":0.14,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:20:34.728Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T03:20:34.728Z"}},{"iob":0.129,"basaliob":0.129,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:25:34.728Z","iobWithZeroTemp":{"iob":-0.065,"basaliob":-0.065,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:34.728Z"}},{"iob":0.119,"basaliob":0.119,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2023-12-23T03:30:34.728Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:34.728Z"}},{"iob":0.11,"basaliob":0.11,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:35:34.728Z","iobWithZeroTemp":{"iob":-0.097,"basaliob":-0.097,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:34.728Z"}},{"iob":0.101,"basaliob":0.101,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:40:34.728Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:34.728Z"}},{"iob":0.093,"basaliob":0.093,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:45:34.728Z","iobWithZeroTemp":{"iob":-0.125,"basaliob":-0.125,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:34.728Z"}},{"iob":0.085,"basaliob":0.085,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T03:50:34.728Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:34.728Z"}},{"iob":0.078,"basaliob":0.078,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T03:55:34.728Z","iobWithZeroTemp":{"iob":-0.149,"basaliob":-0.149,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:34.728Z"}},{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T04:00:34.728Z","iobWithZeroTemp":{"iob":-0.159,"basaliob":-0.159,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:34.728Z"}},{"iob":0.065,"basaliob":0.065,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T04:05:34.728Z","iobWithZeroTemp":{"iob":-0.17,"basaliob":-0.17,"bolussnooze":0,"activity":-7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:34.728Z"}},{"iob":0.06,"basaliob":0.06,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:10:34.728Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:34.728Z"}},{"iob":0.055,"basaliob":0.055,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:15:34.728Z","iobWithZeroTemp":{"iob":-0.187,"basaliob":-0.187,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2023-12-23T04:15:34.728Z"}},{"iob":0.05,"basaliob":0.05,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:20:34.728Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.728Z"}},{"iob":0.045,"basaliob":0.045,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:25:34.728Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:34.728Z"}},{"iob":0.041,"basaliob":0.041,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:30:34.728Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:34.728Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:35:34.728Z","iobWithZeroTemp":{"iob":-0.215,"basaliob":-0.215,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:34.728Z"}},{"iob":0.034,"basaliob":0.034,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:34.728Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:40:34.728Z"}},{"iob":0.031,"basaliob":0.031,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:34.728Z","iobWithZeroTemp":{"iob":-0.225,"basaliob":-0.225,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:34.728Z"}},{"iob":0.028,"basaliob":0.028,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:34.728Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:50:34.728Z"}},{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:34.728Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T04:55:34.728Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:34.728Z","iobWithZeroTemp":{"iob":-0.238,"basaliob":-0.238,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T05:00:34.728Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:34.728Z","iobWithZeroTemp":{"iob":-0.242,"basaliob":-0.242,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:34.728Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:34.728Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:10:34.728Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:34.728Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:34.728Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:34.728Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:20:34.728Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:34.728Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:34.728Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:34.728Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:30:34.728Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:34.728Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:34.728Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:34.728Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:40:34.728Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:34.728Z","iobWithZeroTemp":{"iob":-0.261,"basaliob":-0.261,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:45:34.728Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:34.728Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:34.728Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:34.728Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:55:34.728Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:34.728Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:00:34.728Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:05:34.728Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:05:34.728Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:10:34.728Z","iobWithZeroTemp":{"iob":-0.267,"basaliob":-0.267,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:10:34.728Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:15:34.728Z","iobWithZeroTemp":{"iob":-0.267,"basaliob":-0.267,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:15:34.728Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units": "mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-1.5617,"slopeFromMinDeviation":2.3415,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703298035878,"flatBGsDetected":false},"output":{"temp":"absolute","bg":90,"tick":-6,"eventualBG":-3,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:20:35.878Z","sensitivityRatio":1,"predBGs":{"IOB":[90,84,78,73,68,64,60,56,53,50,47,45,43,42,40,39],"ZT":[90,87,84,81,78,76,74,72,70,68,67,66,65,64,64,63,63,63,63,63,63,64,64,65,66,67,68,69,70,71,72,73,75,76,77,79,80,82,84,85,87,89,90]},"COB":0,"IOB":0.336,"reason":"COB: 0, Dev: -45, BGI: -3, ISF: 144, CR: 18.5, Target: 91, minPredBG 51, minGuardBG 23, IOBpredBG 39; 1 add'l carbs req w\/in 25m; minGuardBG 23<66","carbsReq":1,"carbsReqWithin":25,"duration":120,"rate":0,"timestamp":"2023-12-23T02:20:35.885Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_032535.json b/app/src/androidTest/assets/results/2023-12-23_032535.json new file mode 100644 index 00000000000..8d7872161be --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_032535.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":87,"noise":0,"delta":-3.72,"short_avgdelta":-3.72,"long_avgdelta":-9.04,"date":1703298300000,"dura_ISF_minutes":5,"dura_ISF_average":88.5,"parabola_fit_correlation":0.9982,"parabola_fit_minutes":15,"parabola_fit_last_delta":-2.6000000000000334,"parabola_fit_next_delta":-0.6000000000001116,"parabola_fit_a0":87.1,"parabola_fit_a1":-1.6,"parabola_fit_a2":1,"bg_acceleration":1.999999999999922},"currenttemp":{"temp":"absolute","duration":115,"rate":0,"minutesrunning":5},"iob_data":[{"iob":0.293,"basaliob":0.293,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.494Z","iobWithZeroTemp":{"iob":0.293,"basaliob":0.293,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2023-12-23T02:25:34.494Z"}},{"iob":0.273,"basaliob":0.273,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.494Z","iobWithZeroTemp":{"iob":0.256,"basaliob":0.256,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2023-12-23T02:30:34.494Z"}},{"iob":0.254,"basaliob":0.254,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:34.494Z","iobWithZeroTemp":{"iob":0.217,"basaliob":0.217,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2023-12-23T02:35:34.494Z"}},{"iob":0.236,"basaliob":0.236,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2023-12-23T02:40:34.494Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:34.494Z"}},{"iob":0.219,"basaliob":0.219,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2023-12-23T02:45:34.494Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:34.494Z"}},{"iob":0.203,"basaliob":0.203,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:50:34.494Z","iobWithZeroTemp":{"iob":0.106,"basaliob":0.106,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:34.494Z"}},{"iob":0.187,"basaliob":0.187,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2023-12-23T02:55:34.494Z","iobWithZeroTemp":{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:34.494Z"}},{"iob":0.173,"basaliob":0.173,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2023-12-23T03:00:34.494Z","iobWithZeroTemp":{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:00:34.494Z"}},{"iob":0.16,"basaliob":0.16,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2023-12-23T03:05:34.494Z","iobWithZeroTemp":{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:05:34.494Z"}},{"iob":0.148,"basaliob":0.148,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:10:34.494Z","iobWithZeroTemp":{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:10:34.494Z"}},{"iob":0.136,"basaliob":0.136,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:15:34.494Z","iobWithZeroTemp":{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:34.494Z"}},{"iob":0.125,"basaliob":0.125,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:20:34.494Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T03:20:34.494Z"}},{"iob":0.115,"basaliob":0.115,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:25:34.494Z","iobWithZeroTemp":{"iob":-0.065,"basaliob":-0.065,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:34.494Z"}},{"iob":0.106,"basaliob":0.106,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:30:34.494Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:34.494Z"}},{"iob":0.097,"basaliob":0.097,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:35:34.494Z","iobWithZeroTemp":{"iob":-0.098,"basaliob":-0.098,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:34.494Z"}},{"iob":0.089,"basaliob":0.089,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:40:34.494Z","iobWithZeroTemp":{"iob":-0.112,"basaliob":-0.112,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:34.494Z"}},{"iob":0.082,"basaliob":0.082,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T03:45:34.494Z","iobWithZeroTemp":{"iob":-0.125,"basaliob":-0.125,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:34.494Z"}},{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:50:34.494Z","iobWithZeroTemp":{"iob":-0.137,"basaliob":-0.137,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:34.494Z"}},{"iob":0.068,"basaliob":0.068,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T03:55:34.494Z","iobWithZeroTemp":{"iob":-0.149,"basaliob":-0.149,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:34.494Z"}},{"iob":0.062,"basaliob":0.062,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:00:34.494Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:34.494Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T04:05:34.494Z","iobWithZeroTemp":{"iob":-0.169,"basaliob":-0.169,"bolussnooze":0,"activity":-7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:34.494Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:10:34.494Z","iobWithZeroTemp":{"iob":-0.178,"basaliob":-0.178,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:34.494Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:15:34.494Z","iobWithZeroTemp":{"iob":-0.187,"basaliob":-0.187,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2023-12-23T04:15:34.494Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:20:34.494Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:34.494Z"}},{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:25:34.494Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:34.494Z"}},{"iob":0.035,"basaliob":0.035,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:30:34.494Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:34.494Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:35:34.494Z","iobWithZeroTemp":{"iob":-0.214,"basaliob":-0.214,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:35:34.494Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:34.494Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:40:34.494Z"}},{"iob":0.026,"basaliob":0.026,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:34.494Z","iobWithZeroTemp":{"iob":-0.225,"basaliob":-0.225,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:34.494Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:34.494Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:50:34.494Z"}},{"iob":0.021,"basaliob":0.021,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:34.494Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:55:34.494Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:34.494Z","iobWithZeroTemp":{"iob":-0.238,"basaliob":-0.238,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2023-12-23T05:00:34.494Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:34.494Z","iobWithZeroTemp":{"iob":-0.241,"basaliob":-0.241,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:34.494Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:34.494Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:10:34.494Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:34.494Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:34.494Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:34.494Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:20:34.494Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:34.494Z","iobWithZeroTemp":{"iob":-0.253,"basaliob":-0.253,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:34.494Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:34.494Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:30:34.494Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:34.494Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:34.494Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:34.494Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:40:34.494Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:34.494Z","iobWithZeroTemp":{"iob":-0.261,"basaliob":-0.261,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:45:34.494Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:34.494Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:50:34.494Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:34.494Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T05:55:34.494Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:34.494Z","iobWithZeroTemp":{"iob":-0.264,"basaliob":-0.264,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:00:34.494Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:05:34.494Z","iobWithZeroTemp":{"iob":-0.266,"basaliob":-0.266,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:05:34.494Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:10:34.494Z","iobWithZeroTemp":{"iob":-0.266,"basaliob":-0.266,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:10:34.494Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:15:34.494Z","iobWithZeroTemp":{"iob":-0.268,"basaliob":-0.268,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:15:34.494Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:20:34.494Z","iobWithZeroTemp":{"iob":-0.268,"basaliob":-0.268,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:20:34.494Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7,"autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4, + "out_units": "mg\/dL", + "bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-0.9788181818181818,"slopeFromMinDeviation":2.8432000000000004,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703298335621,"flatBGsDetected":false},"output":{"temp":"absolute","bg":87,"tick":-4,"eventualBG":39,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:25:35.621Z","sensitivityRatio":1,"predBGs":{"IOB":[87,83,79,76,73,70,66,64,61,58,55,53,50,48,46,44,42,41,39],"ZT":[87,82,77,73,69,65,62,59,57,55,53,51,50,49,48,48,48,48,48,49,50,51,52,53,54,56,57,59,61,63,65,67,70,72,75,77,79,82,85,87,90],"UAM":[87,82,78,73,69,65,62,58,55,52,49,47,44,42,40,39]},"COB":0,"IOB":0.293,"reason":"COB: 0, Dev: 7, BGI: -5, ISF: 235, CR: 18.5, Target: 91, minPredBG 44, minGuardBG 16, IOBpredBG 39, UAMpredBG 39; 1 add'l carbs req w\/in 35m; minGuardBG 16<66 115m left and 0 ~ req 0U\/hr: no temp required","carbsReq":1,"carbsReqWithin":35,"timestamp":"2023-12-23T02:25:35.630Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_033036.json b/app/src/androidTest/assets/results/2023-12-23_033036.json new file mode 100644 index 00000000000..04455220c39 --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_033036.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":78,"noise":0,"delta":-6.78,"short_avgdelta":-6.78,"long_avgdelta":-7.98,"date":1703298600000,"dura_ISF_minutes":0,"dura_ISF_average":78,"parabola_fit_correlation":0.9884,"parabola_fit_minutes":45,"parabola_fit_last_delta":-2.006060606060996,"parabola_fit_next_delta":0.16060606060569124,"parabola_fit_a0":81.7,"parabola_fit_a1":-0.92,"parabola_fit_a2":1.08,"bg_acceleration":2.166666666666687},"currenttemp":{"temp":"absolute","duration":110,"rate":0,"minutesrunning":10},"iob_data":[{"iob":0.252,"basaliob":0.252,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2023-12-23T02:30:35.003Z","iobWithZeroTemp":{"iob":0.252,"basaliob":0.252,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2023-12-23T02:30:35.003Z"}},{"iob":0.233,"basaliob":0.233,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:35.003Z","iobWithZeroTemp":{"iob":0.216,"basaliob":0.216,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2023-12-23T02:35:35.003Z"}},{"iob":0.215,"basaliob":0.215,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2023-12-23T02:40:35.003Z","iobWithZeroTemp":{"iob":0.178,"basaliob":0.178,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2023-12-23T02:40:35.003Z"}},{"iob":0.199,"basaliob":0.199,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2023-12-23T02:45:35.003Z","iobWithZeroTemp":{"iob":0.141,"basaliob":0.141,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2023-12-23T02:45:35.003Z"}},{"iob":0.183,"basaliob":0.183,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2023-12-23T02:50:35.003Z","iobWithZeroTemp":{"iob":0.105,"basaliob":0.105,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:50:35.003Z"}},{"iob":0.169,"basaliob":0.169,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2023-12-23T02:55:35.003Z","iobWithZeroTemp":{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2023-12-23T02:55:35.003Z"}},{"iob":0.155,"basaliob":0.155,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2023-12-23T03:00:35.003Z","iobWithZeroTemp":{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2023-12-23T03:00:35.003Z"}},{"iob":0.142,"basaliob":0.142,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2023-12-23T03:05:35.003Z","iobWithZeroTemp":{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:05:35.003Z"}},{"iob":0.131,"basaliob":0.131,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2023-12-23T03:10:35.003Z","iobWithZeroTemp":{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2023-12-23T03:10:35.003Z"}},{"iob":0.12,"basaliob":0.12,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2023-12-23T03:15:35.003Z","iobWithZeroTemp":{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:15:35.003Z"}},{"iob":0.11,"basaliob":0.11,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2023-12-23T03:20:35.003Z","iobWithZeroTemp":{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T03:20:35.003Z"}},{"iob":0.101,"basaliob":0.101,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2023-12-23T03:25:35.003Z","iobWithZeroTemp":{"iob":-0.065,"basaliob":-0.065,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:25:35.003Z"}},{"iob":0.092,"basaliob":0.092,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2023-12-23T03:30:35.003Z","iobWithZeroTemp":{"iob":-0.082,"basaliob":-0.082,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:30:35.003Z"}},{"iob":0.084,"basaliob":0.084,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2023-12-23T03:35:35.003Z","iobWithZeroTemp":{"iob":-0.097,"basaliob":-0.097,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:35:35.003Z"}},{"iob":0.077,"basaliob":0.077,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2023-12-23T03:40:35.003Z","iobWithZeroTemp":{"iob":-0.111,"basaliob":-0.111,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:40:35.003Z"}},{"iob":0.07,"basaliob":0.07,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2023-12-23T03:45:35.003Z","iobWithZeroTemp":{"iob":-0.125,"basaliob":-0.125,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:45:35.003Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2023-12-23T03:50:35.003Z","iobWithZeroTemp":{"iob":-0.138,"basaliob":-0.138,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:50:35.003Z"}},{"iob":0.058,"basaliob":0.058,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2023-12-23T03:55:35.003Z","iobWithZeroTemp":{"iob":-0.149,"basaliob":-0.149,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2023-12-23T03:55:35.003Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2023-12-23T04:00:35.003Z","iobWithZeroTemp":{"iob":-0.16,"basaliob":-0.16,"bolussnooze":0,"activity":-6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:00:35.003Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:35.003Z","iobWithZeroTemp":{"iob":-0.17,"basaliob":-0.17,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:05:35.003Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:35.003Z","iobWithZeroTemp":{"iob":-0.179,"basaliob":-0.179,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:10:35.003Z"}},{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:15:35.003Z","iobWithZeroTemp":{"iob":-0.187,"basaliob":-0.187,"bolussnooze":0,"activity":-0.001,"lastBolusTime":0,"time":"2023-12-23T04:15:35.003Z"}},{"iob":0.035,"basaliob":0.035,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:20:35.003Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2023-12-23T04:20:35.003Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:25:35.003Z","iobWithZeroTemp":{"iob":-0.202,"basaliob":-0.202,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2023-12-23T04:25:35.003Z"}},{"iob":0.028,"basaliob":0.028,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:30:35.003Z","iobWithZeroTemp":{"iob":-0.209,"basaliob":-0.209,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2023-12-23T04:30:35.003Z"}},{"iob":0.026,"basaliob":0.026,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:35:35.003Z","iobWithZeroTemp":{"iob":-0.214,"basaliob":-0.214,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2023-12-23T04:35:35.003Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:40:35.003Z","iobWithZeroTemp":{"iob":-0.22,"basaliob":-0.22,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2023-12-23T04:40:35.003Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:45:35.003Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2023-12-23T04:45:35.003Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:50:35.003Z","iobWithZeroTemp":{"iob":-0.23,"basaliob":-0.23,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:50:35.003Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2023-12-23T04:55:35.003Z","iobWithZeroTemp":{"iob":-0.234,"basaliob":-0.234,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2023-12-23T04:55:35.003Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:00:35.003Z","iobWithZeroTemp":{"iob":-0.238,"basaliob":-0.238,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:00:35.003Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:05:35.003Z","iobWithZeroTemp":{"iob":-0.241,"basaliob":-0.241,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:05:35.003Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:10:35.003Z","iobWithZeroTemp":{"iob":-0.245,"basaliob":-0.245,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2023-12-23T05:10:35.003Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:15:35.003Z","iobWithZeroTemp":{"iob":-0.248,"basaliob":-0.248,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2023-12-23T05:15:35.003Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:20:35.003Z","iobWithZeroTemp":{"iob":-0.25,"basaliob":-0.25,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:20:35.003Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:25:35.003Z","iobWithZeroTemp":{"iob":-0.252,"basaliob":-0.252,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:25:35.003Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:30:35.003Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2023-12-23T05:30:35.003Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:35:35.003Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2023-12-23T05:35:35.003Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:40:35.003Z","iobWithZeroTemp":{"iob":-0.259,"basaliob":-0.259,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:40:35.003Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:45:35.003Z","iobWithZeroTemp":{"iob":-0.261,"basaliob":-0.261,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:45:35.003Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:50:35.003Z","iobWithZeroTemp":{"iob":-0.262,"basaliob":-0.262,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:50:35.003Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T05:55:35.003Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T05:55:35.003Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:00:35.003Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2023-12-23T06:00:35.003Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:05:35.003Z","iobWithZeroTemp":{"iob":-0.265,"basaliob":-0.265,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:05:35.003Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:10:35.003Z","iobWithZeroTemp":{"iob":-0.266,"basaliob":-0.266,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:10:35.003Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:15:35.003Z","iobWithZeroTemp":{"iob":-0.268,"basaliob":-0.268,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:15:35.003Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2023-12-23T06:20:35.003Z","iobWithZeroTemp":{"iob":-0.268,"basaliob":-0.268,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2023-12-23T06:20:35.003Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2023-12-23T06:25:35.003Z","iobWithZeroTemp":{"iob":-0.268,"basaliob":-0.268,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2023-12-23T06:25:35.003Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":18.5,"sens":150,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.25,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units": "mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":4,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-0.8075454545454546,"slopeFromMinDeviation":2.2333333333333334,"lastBolusTime":1703214924154,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1703298636316,"flatBGsDetected":false},"output":{"temp":"absolute","bg":78,"tick":-7,"eventualBG":-10,"targetBG":91,"insulinReq":0,"deliverAt":"2023-12-23T02:30:36.316Z","sensitivityRatio":1,"predBGs":{"IOB":[78,71,65,59,54,49,44,40,39,39,39,39,39],"ZT":[78,72,67,62,57,53,49,46,43,41,39,39,39,39,39,39,39,39,39,39,39,39,41,43,45,47,49,51,54,57,59,62,65,68,71,75,78,81,85,88]},"COB":0,"IOB":0.252,"reason":"COB: 0, Dev: -13, BGI: -6, ISF: 299, CR: 18.5, Target: 91, minPredBG 35, minGuardBG -6, IOBpredBG 39; 4 add'l carbs req w\/in 10m; minGuardBG -6<66 110m left and 0 ~ req 0U\/hr: no temp required","carbsReq":4,"carbsReqWithin":10,"timestamp":"2023-12-23T02:30:36.327Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2023-12-23_033541.json b/app/src/androidTest/assets/results/2023-12-23_033541.json new file mode 100644 index 00000000000..162fe5e3618 --- /dev/null +++ b/app/src/androidTest/assets/results/2023-12-23_033541.json @@ -0,0 +1,952 @@ +{ + "algorithm": "OpenAPSSMBAutoISFPlugin", + "input": { + "glucoseStatus": { + "glucose": 64, + "noise": 0, + "delta": -11.39, + "short_avgdelta": -11.39, + "long_avgdelta": -8.27, + "date": 1703298900000, + "dura_ISF_minutes": 0, + "dura_ISF_average": 64, + "parabola_fit_correlation": 0.9999, + "parabola_fit_minutes": 15, + "parabola_fit_last_delta": -14.199999999999857, + "parabola_fit_next_delta": -19.700000000000006, + "parabola_fit_a0": 63.9, + "parabola_fit_a1": -16.95, + "parabola_fit_a2": -2.75, + "bg_acceleration": -5.500000000000149 + }, + "currenttemp": { + "temp": "absolute", + "duration": 105, + "rate": 0, + "minutesrunning": 15 + }, + "iob_data": [ + { + "iob": 0.212, + "basaliob": 0.212, + "bolussnooze": 0, + "activity": 0.0037, + "lastBolusTime": 0, + "time": "2023-12-23T02:35:38.340Z", + "iobWithZeroTemp": { + "iob": 0.212, + "basaliob": 0.212, + "bolussnooze": 0, + "activity": 0.0037, + "lastBolusTime": 0, + "time": "2023-12-23T02:35:38.340Z" + } + }, + { + "iob": 0.194, + "basaliob": 0.194, + "bolussnooze": 0, + "activity": 0.0034, + "lastBolusTime": 0, + "time": "2023-12-23T02:40:38.340Z", + "iobWithZeroTemp": { + "iob": 0.177, + "basaliob": 0.177, + "bolussnooze": 0, + "activity": 0.0034, + "lastBolusTime": 0, + "time": "2023-12-23T02:40:38.340Z" + } + }, + { + "iob": 0.178, + "basaliob": 0.178, + "bolussnooze": 0, + "activity": 0.0031, + "lastBolusTime": 0, + "time": "2023-12-23T02:45:38.340Z", + "iobWithZeroTemp": { + "iob": 0.141, + "basaliob": 0.141, + "bolussnooze": 0, + "activity": 0.003, + "lastBolusTime": 0, + "time": "2023-12-23T02:45:38.340Z" + } + }, + { + "iob": 0.163, + "basaliob": 0.163, + "bolussnooze": 0, + "activity": 0.0029, + "lastBolusTime": 0, + "time": "2023-12-23T02:50:38.340Z", + "iobWithZeroTemp": { + "iob": 0.105, + "basaliob": 0.105, + "bolussnooze": 0, + "activity": 0.0028, + "lastBolusTime": 0, + "time": "2023-12-23T02:50:38.340Z" + } + }, + { + "iob": 0.149, + "basaliob": 0.149, + "bolussnooze": 0, + "activity": 0.0027, + "lastBolusTime": 0, + "time": "2023-12-23T02:55:38.340Z", + "iobWithZeroTemp": { + "iob": 0.071, + "basaliob": 0.071, + "bolussnooze": 0, + "activity": 0.0025, + "lastBolusTime": 0, + "time": "2023-12-23T02:55:38.340Z" + } + }, + { + "iob": 0.136, + "basaliob": 0.136, + "bolussnooze": 0, + "activity": 0.0025, + "lastBolusTime": 0, + "time": "2023-12-23T03:00:38.340Z", + "iobWithZeroTemp": { + "iob": 0.039, + "basaliob": 0.039, + "bolussnooze": 0, + "activity": 0.0022, + "lastBolusTime": 0, + "time": "2023-12-23T03:00:38.340Z" + } + }, + { + "iob": 0.124, + "basaliob": 0.124, + "bolussnooze": 0, + "activity": 0.0023, + "lastBolusTime": 0, + "time": "2023-12-23T03:05:38.340Z", + "iobWithZeroTemp": { + "iob": 0.015, + "basaliob": 0.015, + "bolussnooze": 0, + "activity": 0.0019, + "lastBolusTime": 0, + "time": "2023-12-23T03:05:38.340Z" + } + }, + { + "iob": 0.113, + "basaliob": 0.113, + "bolussnooze": 0, + "activity": 0.0021, + "lastBolusTime": 0, + "time": "2023-12-23T03:10:38.340Z", + "iobWithZeroTemp": { + "iob": -0.007, + "basaliob": -0.007, + "bolussnooze": 0, + "activity": 0.0016, + "lastBolusTime": 0, + "time": "2023-12-23T03:10:38.340Z" + } + }, + { + "iob": 0.103, + "basaliob": 0.103, + "bolussnooze": 0, + "activity": 0.0019, + "lastBolusTime": 0, + "time": "2023-12-23T03:15:38.340Z", + "iobWithZeroTemp": { + "iob": -0.028, + "basaliob": -0.028, + "bolussnooze": 0, + "activity": 0.0013, + "lastBolusTime": 0, + "time": "2023-12-23T03:15:38.340Z" + } + }, + { + "iob": 0.094, + "basaliob": 0.094, + "bolussnooze": 0, + "activity": 0.0018, + "lastBolusTime": 0, + "time": "2023-12-23T03:20:38.340Z", + "iobWithZeroTemp": { + "iob": -0.047, + "basaliob": -0.047, + "bolussnooze": 0, + "activity": 0.001, + "lastBolusTime": 0, + "time": "2023-12-23T03:20:38.340Z" + } + }, + { + "iob": 0.085, + "basaliob": 0.085, + "bolussnooze": 0, + "activity": 0.0016, + "lastBolusTime": 0, + "time": "2023-12-23T03:25:38.340Z", + "iobWithZeroTemp": { + "iob": -0.065, + "basaliob": -0.065, + "bolussnooze": 0, + "activity": 0.0007, + "lastBolusTime": 0, + "time": "2023-12-23T03:25:38.340Z" + } + }, + { + "iob": 0.077, + "basaliob": 0.077, + "bolussnooze": 0, + "activity": 0.0015, + "lastBolusTime": 0, + "time": "2023-12-23T03:30:38.340Z", + "iobWithZeroTemp": { + "iob": -0.082, + "basaliob": -0.082, + "bolussnooze": 0, + "activity": 0.0005, + "lastBolusTime": 0, + "time": "2023-12-23T03:30:38.340Z" + } + }, + { + "iob": 0.07, + "basaliob": 0.07, + "bolussnooze": 0, + "activity": 0.0014, + "lastBolusTime": 0, + "time": "2023-12-23T03:35:38.340Z", + "iobWithZeroTemp": { + "iob": -0.097, + "basaliob": -0.097, + "bolussnooze": 0, + "activity": 0.0003, + "lastBolusTime": 0, + "time": "2023-12-23T03:35:38.340Z" + } + }, + { + "iob": 0.063, + "basaliob": 0.063, + "bolussnooze": 0, + "activity": 0.0013, + "lastBolusTime": 0, + "time": "2023-12-23T03:40:38.340Z", + "iobWithZeroTemp": { + "iob": -0.112, + "basaliob": -0.112, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T03:40:38.340Z" + } + }, + { + "iob": 0.057, + "basaliob": 0.057, + "bolussnooze": 0, + "activity": 0.0012, + "lastBolusTime": 0, + "time": "2023-12-23T03:45:38.340Z", + "iobWithZeroTemp": { + "iob": -0.125, + "basaliob": -0.125, + "bolussnooze": 0, + "activity": -0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T03:45:38.340Z" + } + }, + { + "iob": 0.052, + "basaliob": 0.052, + "bolussnooze": 0, + "activity": 0.0011, + "lastBolusTime": 0, + "time": "2023-12-23T03:50:38.340Z", + "iobWithZeroTemp": { + "iob": -0.137, + "basaliob": -0.137, + "bolussnooze": 0, + "activity": -0.0002, + "lastBolusTime": 0, + "time": "2023-12-23T03:50:38.340Z" + } + }, + { + "iob": 0.046, + "basaliob": 0.046, + "bolussnooze": 0, + "activity": 0.001, + "lastBolusTime": 0, + "time": "2023-12-23T03:55:38.340Z", + "iobWithZeroTemp": { + "iob": -0.15, + "basaliob": -0.15, + "bolussnooze": 0, + "activity": -0.0004, + "lastBolusTime": 0, + "time": "2023-12-23T03:55:38.340Z" + } + }, + { + "iob": 0.042, + "basaliob": 0.042, + "bolussnooze": 0, + "activity": 0.0009, + "lastBolusTime": 0, + "time": "2023-12-23T04:00:38.340Z", + "iobWithZeroTemp": { + "iob": -0.16, + "basaliob": -0.16, + "bolussnooze": 0, + "activity": -0.0006, + "lastBolusTime": 0, + "time": "2023-12-23T04:00:38.340Z" + } + }, + { + "iob": 0.038, + "basaliob": 0.038, + "bolussnooze": 0, + "activity": 0.0008, + "lastBolusTime": 0, + "time": "2023-12-23T04:05:38.340Z", + "iobWithZeroTemp": { + "iob": -0.169, + "basaliob": -0.169, + "bolussnooze": 0, + "activity": -0.0008, + "lastBolusTime": 0, + "time": "2023-12-23T04:05:38.340Z" + } + }, + { + "iob": 0.034, + "basaliob": 0.034, + "bolussnooze": 0, + "activity": 0.0007, + "lastBolusTime": 0, + "time": "2023-12-23T04:10:38.340Z", + "iobWithZeroTemp": { + "iob": -0.178, + "basaliob": -0.178, + "bolussnooze": 0, + "activity": -0.001, + "lastBolusTime": 0, + "time": "2023-12-23T04:10:38.340Z" + } + }, + { + "iob": 0.03, + "basaliob": 0.03, + "bolussnooze": 0, + "activity": 0.0007, + "lastBolusTime": 0, + "time": "2023-12-23T04:15:38.340Z", + "iobWithZeroTemp": { + "iob": -0.187, + "basaliob": -0.187, + "bolussnooze": 0, + "activity": -0.001, + "lastBolusTime": 0, + "time": "2023-12-23T04:15:38.340Z" + } + }, + { + "iob": 0.027, + "basaliob": 0.027, + "bolussnooze": 0, + "activity": 0.0006, + "lastBolusTime": 0, + "time": "2023-12-23T04:20:38.340Z", + "iobWithZeroTemp": { + "iob": -0.195, + "basaliob": -0.195, + "bolussnooze": 0, + "activity": -0.0012, + "lastBolusTime": 0, + "time": "2023-12-23T04:20:38.340Z" + } + }, + { + "iob": 0.024, + "basaliob": 0.024, + "bolussnooze": 0, + "activity": 0.0006, + "lastBolusTime": 0, + "time": "2023-12-23T04:25:38.340Z", + "iobWithZeroTemp": { + "iob": -0.202, + "basaliob": -0.202, + "bolussnooze": 0, + "activity": -0.0013, + "lastBolusTime": 0, + "time": "2023-12-23T04:25:38.340Z" + } + }, + { + "iob": 0.021, + "basaliob": 0.021, + "bolussnooze": 0, + "activity": 0.0005, + "lastBolusTime": 0, + "time": "2023-12-23T04:30:38.340Z", + "iobWithZeroTemp": { + "iob": -0.209, + "basaliob": -0.209, + "bolussnooze": 0, + "activity": -0.0014, + "lastBolusTime": 0, + "time": "2023-12-23T04:30:38.340Z" + } + }, + { + "iob": 0.019, + "basaliob": 0.019, + "bolussnooze": 0, + "activity": 0.0005, + "lastBolusTime": 0, + "time": "2023-12-23T04:35:38.340Z", + "iobWithZeroTemp": { + "iob": -0.214, + "basaliob": -0.214, + "bolussnooze": 0, + "activity": -0.0015, + "lastBolusTime": 0, + "time": "2023-12-23T04:35:38.340Z" + } + }, + { + "iob": 0.017, + "basaliob": 0.017, + "bolussnooze": 0, + "activity": 0.0004, + "lastBolusTime": 0, + "time": "2023-12-23T04:40:38.340Z", + "iobWithZeroTemp": { + "iob": -0.22, + "basaliob": -0.22, + "bolussnooze": 0, + "activity": -0.0016, + "lastBolusTime": 0, + "time": "2023-12-23T04:40:38.340Z" + } + }, + { + "iob": 0.015, + "basaliob": 0.015, + "bolussnooze": 0, + "activity": 0.0004, + "lastBolusTime": 0, + "time": "2023-12-23T04:45:38.340Z", + "iobWithZeroTemp": { + "iob": -0.225, + "basaliob": -0.225, + "bolussnooze": 0, + "activity": -0.0017, + "lastBolusTime": 0, + "time": "2023-12-23T04:45:38.340Z" + } + }, + { + "iob": 0.013, + "basaliob": 0.013, + "bolussnooze": 0, + "activity": 0.0003, + "lastBolusTime": 0, + "time": "2023-12-23T04:50:38.340Z", + "iobWithZeroTemp": { + "iob": -0.23, + "basaliob": -0.23, + "bolussnooze": 0, + "activity": -0.0018, + "lastBolusTime": 0, + "time": "2023-12-23T04:50:38.340Z" + } + }, + { + "iob": 0.011, + "basaliob": 0.011, + "bolussnooze": 0, + "activity": 0.0003, + "lastBolusTime": 0, + "time": "2023-12-23T04:55:38.340Z", + "iobWithZeroTemp": { + "iob": -0.234, + "basaliob": -0.234, + "bolussnooze": 0, + "activity": -0.0019, + "lastBolusTime": 0, + "time": "2023-12-23T04:55:38.340Z" + } + }, + { + "iob": 0.01, + "basaliob": 0.01, + "bolussnooze": 0, + "activity": 0.0003, + "lastBolusTime": 0, + "time": "2023-12-23T05:00:38.340Z", + "iobWithZeroTemp": { + "iob": -0.238, + "basaliob": -0.238, + "bolussnooze": 0, + "activity": -0.0019, + "lastBolusTime": 0, + "time": "2023-12-23T05:00:38.340Z" + } + }, + { + "iob": 0.008, + "basaliob": 0.008, + "bolussnooze": 0, + "activity": 0.0003, + "lastBolusTime": 0, + "time": "2023-12-23T05:05:38.340Z", + "iobWithZeroTemp": { + "iob": -0.242, + "basaliob": -0.242, + "bolussnooze": 0, + "activity": -0.0019, + "lastBolusTime": 0, + "time": "2023-12-23T05:05:38.340Z" + } + }, + { + "iob": 0.007, + "basaliob": 0.007, + "bolussnooze": 0, + "activity": 0.0002, + "lastBolusTime": 0, + "time": "2023-12-23T05:10:38.340Z", + "iobWithZeroTemp": { + "iob": -0.245, + "basaliob": -0.245, + "bolussnooze": 0, + "activity": -0.0021, + "lastBolusTime": 0, + "time": "2023-12-23T05:10:38.340Z" + } + }, + { + "iob": 0.006, + "basaliob": 0.006, + "bolussnooze": 0, + "activity": 0.0002, + "lastBolusTime": 0, + "time": "2023-12-23T05:15:38.340Z", + "iobWithZeroTemp": { + "iob": -0.248, + "basaliob": -0.248, + "bolussnooze": 0, + "activity": -0.0021, + "lastBolusTime": 0, + "time": "2023-12-23T05:15:38.340Z" + } + }, + { + "iob": 0.005, + "basaliob": 0.005, + "bolussnooze": 0, + "activity": 0.0002, + "lastBolusTime": 0, + "time": "2023-12-23T05:20:38.340Z", + "iobWithZeroTemp": { + "iob": -0.251, + "basaliob": -0.251, + "bolussnooze": 0, + "activity": -0.0021, + "lastBolusTime": 0, + "time": "2023-12-23T05:20:38.340Z" + } + }, + { + "iob": 0.004, + "basaliob": 0.004, + "bolussnooze": 0, + "activity": 0.0002, + "lastBolusTime": 0, + "time": "2023-12-23T05:25:38.340Z", + "iobWithZeroTemp": { + "iob": -0.253, + "basaliob": -0.253, + "bolussnooze": 0, + "activity": -0.0022, + "lastBolusTime": 0, + "time": "2023-12-23T05:25:38.340Z" + } + }, + { + "iob": 0.004, + "basaliob": 0.004, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:30:38.340Z", + "iobWithZeroTemp": { + "iob": -0.255, + "basaliob": -0.255, + "bolussnooze": 0, + "activity": -0.0023, + "lastBolusTime": 0, + "time": "2023-12-23T05:30:38.340Z" + } + }, + { + "iob": 0.003, + "basaliob": 0.003, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:35:38.340Z", + "iobWithZeroTemp": { + "iob": -0.257, + "basaliob": -0.257, + "bolussnooze": 0, + "activity": -0.0023, + "lastBolusTime": 0, + "time": "2023-12-23T05:35:38.340Z" + } + }, + { + "iob": 0.002, + "basaliob": 0.002, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:40:38.340Z", + "iobWithZeroTemp": { + "iob": -0.259, + "basaliob": -0.259, + "bolussnooze": 0, + "activity": -0.0023, + "lastBolusTime": 0, + "time": "2023-12-23T05:40:38.340Z" + } + }, + { + "iob": 0.002, + "basaliob": 0.002, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:45:38.340Z", + "iobWithZeroTemp": { + "iob": -0.26, + "basaliob": -0.26, + "bolussnooze": 0, + "activity": -0.0024, + "lastBolusTime": 0, + "time": "2023-12-23T05:45:38.340Z" + } + }, + { + "iob": 0.001, + "basaliob": 0.001, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:50:38.340Z", + "iobWithZeroTemp": { + "iob": -0.262, + "basaliob": -0.262, + "bolussnooze": 0, + "activity": -0.0024, + "lastBolusTime": 0, + "time": "2023-12-23T05:50:38.340Z" + } + }, + { + "iob": 0.001, + "basaliob": 0.001, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T05:55:38.340Z", + "iobWithZeroTemp": { + "iob": -0.263, + "basaliob": -0.263, + "bolussnooze": 0, + "activity": -0.0024, + "lastBolusTime": 0, + "time": "2023-12-23T05:55:38.340Z" + } + }, + { + "iob": 0.001, + "basaliob": 0.001, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T06:00:38.340Z", + "iobWithZeroTemp": { + "iob": -0.264, + "basaliob": -0.264, + "bolussnooze": 0, + "activity": -0.0024, + "lastBolusTime": 0, + "time": "2023-12-23T06:00:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0.0001, + "lastBolusTime": 0, + "time": "2023-12-23T06:05:38.340Z", + "iobWithZeroTemp": { + "iob": -0.266, + "basaliob": -0.266, + "bolussnooze": 0, + "activity": -0.0024, + "lastBolusTime": 0, + "time": "2023-12-23T06:05:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0, + "lastBolusTime": 0, + "time": "2023-12-23T06:10:38.340Z", + "iobWithZeroTemp": { + "iob": -0.267, + "basaliob": -0.267, + "bolussnooze": 0, + "activity": -0.0025, + "lastBolusTime": 0, + "time": "2023-12-23T06:10:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0, + "lastBolusTime": 0, + "time": "2023-12-23T06:15:38.340Z", + "iobWithZeroTemp": { + "iob": -0.267, + "basaliob": -0.267, + "bolussnooze": 0, + "activity": -0.0026, + "lastBolusTime": 0, + "time": "2023-12-23T06:15:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0, + "lastBolusTime": 0, + "time": "2023-12-23T06:20:38.340Z", + "iobWithZeroTemp": { + "iob": -0.268, + "basaliob": -0.268, + "bolussnooze": 0, + "activity": -0.0026, + "lastBolusTime": 0, + "time": "2023-12-23T06:20:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0, + "lastBolusTime": 0, + "time": "2023-12-23T06:25:38.340Z", + "iobWithZeroTemp": { + "iob": -0.268, + "basaliob": -0.268, + "bolussnooze": 0, + "activity": -0.0026, + "lastBolusTime": 0, + "time": "2023-12-23T06:25:38.340Z" + } + }, + { + "iob": 0, + "basaliob": 0, + "bolussnooze": 0, + "activity": 0, + "lastBolusTime": 0, + "time": "2023-12-23T06:30:38.340Z", + "iobWithZeroTemp": { + "iob": -0.269, + "basaliob": -0.269, + "bolussnooze": 0, + "activity": -0.0026, + "lastBolusTime": 0, + "time": "2023-12-23T06:30:38.340Z" + } + } + ], + "profile": { + "max_iob": 8, + "type": "current", + "max_daily_basal": 0.45, + "max_basal": 2, + "min_bg": 91, + "max_bg": 91, + "target_bg": 91, + "carb_ratio": 18.5, + "sens": 150.0, + "max_daily_safety_multiplier": 8, + "current_basal_safety_multiplier": 8, + "high_temptarget_raises_sensitivity": true, + "low_temptarget_lowers_sensitivity": false, + "sensitivity_raises_target": false, + "resistance_lowers_target": false, + "adv_target_adjustments": false, + "exercise_mode": true, + "half_basal_exercise_target": 120, + "maxCOB": 120, + "skip_neutral_temps": false, + "remainingCarbsCap": 90, + "enableUAM": true, + "A52_risk_enable": false, + "SMBInterval": 1, + "enableSMB_with_COB": true, + "enableSMB_with_temptarget": true, + "allowSMB_with_high_temptarget": false, + "enableSMB_always": true, + "enableSMB_after_carbs": false, + "maxSMBBasalMinutes": 120, + "maxUAMSMBBasalMinutes": 120, + "bolus_increment": 0.1, + "carbsReqThreshold": 1, + "current_basal": 0.25, + "temptargetSet": false, + "autosens_max": 1.5, + "autosens_min": 0.7, + "out_units": "mg\/dL", + "autoISF_version": "3.0", + "enable_autoISF": true, + "autoISF_max": 4.0, + "autoISF_min": 0.4, + "bgAccel_ISF_weight": 0.3, + "bgBrake_ISF_weight": 0.16, + "enable_pp_ISF_always": true, + "pp_ISF_hours": 10, + "pp_ISF_weight": 0.012, + "delta_ISFrange_weight": 0.13, + "lower_ISFrange_weight": 1.51, + "higher_ISFrange_weight": 0.8, + "enable_dura_ISF_with_COB": true, + "dura_ISF_weight": 1.65, + "smb_delivery_ratio": 0.5, + "smb_delivery_ratio_min": 0.65, + "smb_delivery_ratio_max": 0.95, + "smb_delivery_ratio_bg_range": 45.0, + "smb_max_range_extension": 4.0, + "enableSMB_EvenOn_OddOff": true, + "enableSMB_EvenOn_OddOff_always": true, + "iob_threshold_percent": 60, + "profile_percentage": 100 + }, + "autosens_data": { + "ratio": 1 + }, + "meal_data": { + "carbs": 0, + "mealCOB": 0, + "slopeFromMaxDeviation": -0.6803636363636363, + "slopeFromMinDeviation": 1.405857142857143, + "lastBolusTime": 1703214924154, + "lastCarbTime": 0 + }, + "microBolusAllowed": true, + "currentTime": 1703298941488, + "flatBGsDetected": false + }, + "output": { + "temp": "absolute", + "bg": 64, + "tick": -11, + "eventualBG": -23, + "targetBG": 91, + "insulinReq": 0, + "deliverAt": "2023-12-23T02:35:41.488Z", + "sensitivityRatio": 1, + "variable_sens": 375, + "predBGs": { + "IOB": [ + 64, + 53, + 43, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39 + ], + "ZT": [ + 64, + 57, + 51, + 45, + 40, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 41, + 45, + 48, + 52, + 55, + 59, + 63, + 67, + 71, + 75, + 80, + 84, + 89 + ] + }, + "COB": 0, + "IOB": 0.212, + "reason": "COB: 0, Dev: -8, BGI: -7, ISF: 375, CR: 18.5, Target: 91, minPredBG 17, minGuardBG -43, IOBpredBG 39; 5 add'l carbs req w\/in 0m; minGuardBG -43<66 105m left and 0 ~ req 0U\/hr: no temp required", + "carbsReq": 5, + "carbsReqWithin": 0, + "timestamp": "2023-12-23T02:35:41.500Z" + } +} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_110247.json b/app/src/androidTest/assets/results/2024-01-05_110247.json new file mode 100644 index 00000000000..3c61dfbe4fc --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_110247.json @@ -0,0 +1,4 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":129,"noise":0,"delta":-11.83,"short_avgdelta":-11.83,"long_avgdelta":-10.25,"date":1704448800000,"dura_ISF_minutes":0,"dura_ISF_average":129,"parabola_fit_correlation":0.9992,"parabola_fit_minutes":15,"parabola_fit_last_delta":-12.399999999999896,"parabola_fit_next_delta":-13.899999999999919,"parabola_fit_a0":129.1,"parabola_fit_a1":-13.15,"parabola_fit_a2":-0.75,"bg_acceleration":-1.5000000000000213},"currenttemp":{"temp":"absolute","duration":75,"rate":0,"minutesrunning":15},"iob_data":[{"iob":0.427,"basaliob":0.427,"bolussnooze":0,"activity":0.005,"lastBolusTime":0,"time":"2024-01-05T10:02:44.388Z","iobWithZeroTemp":{"iob":0.427,"basaliob":0.427,"bolussnooze":0,"activity":0.005,"lastBolusTime":0,"time":"2024-01-05T10:02:44.388Z"}},{"iob":0.403,"basaliob":0.403,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2024-01-05T10:07:44.388Z","iobWithZeroTemp":{"iob":0.378,"basaliob":0.378,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2024-01-05T10:07:44.388Z"}},{"iob":0.379,"basaliob":0.379,"bolussnooze":0,"activity":0.0047,"lastBolusTime":0,"time":"2024-01-05T10:12:44.388Z","iobWithZeroTemp":{"iob":0.324,"basaliob":0.324,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2024-01-05T10:12:44.388Z"}},{"iob":0.356,"basaliob":0.356,"bolussnooze":0,"activity":0.0045,"lastBolusTime":0,"time":"2024-01-05T10:17:44.388Z","iobWithZeroTemp":{"iob":0.271,"basaliob":0.271,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:44.388Z"}},{"iob":0.334,"basaliob":0.334,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:22:44.388Z","iobWithZeroTemp":{"iob":0.219,"basaliob":0.219,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:44.388Z"}},{"iob":0.313,"basaliob":0.313,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2024-01-05T10:27:44.388Z","iobWithZeroTemp":{"iob":0.169,"basaliob":0.169,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:27:44.388Z"}},{"iob":0.293,"basaliob":0.293,"bolussnooze":0,"activity":0.0039,"lastBolusTime":0,"time":"2024-01-05T10:32:44.388Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:44.388Z"}},{"iob":0.273,"basaliob":0.273,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2024-01-05T10:37:44.388Z","iobWithZeroTemp":{"iob":0.074,"basaliob":0.074,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:37:44.388Z"}},{"iob":0.255,"basaliob":0.255,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:42:44.388Z","iobWithZeroTemp":{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:42:44.388Z"}},{"iob":0.238,"basaliob":0.238,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2024-01-05T10:47:44.388Z","iobWithZeroTemp":{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:47:44.388Z"}},{"iob":0.221,"basaliob":0.221,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2024-01-05T10:52:44.388Z","iobWithZeroTemp":{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:44.388Z"}},{"iob":0.206,"basaliob":0.206,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:57:44.388Z","iobWithZeroTemp":{"iob":-0.092,"basaliob":-0.092,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T10:57:44.388Z"}},{"iob":0.191,"basaliob":0.191,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T11:02:44.388Z","iobWithZeroTemp":{"iob":-0.129,"basaliob":-0.129,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:44.388Z"}},{"iob":0.177,"basaliob":0.177,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-05T11:07:44.388Z","iobWithZeroTemp":{"iob":-0.164,"basaliob":-0.164,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.388Z"}},{"iob":0.164,"basaliob":0.164,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T11:12:44.388Z","iobWithZeroTemp":{"iob":-0.197,"basaliob":-0.197,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.388Z"}},{"iob":0.152,"basaliob":0.152,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-05T11:17:44.388Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.388Z"}},{"iob":0.14,"basaliob":0.14,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T11:22:44.388Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.388Z"}},{"iob":0.129,"basaliob":0.129,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T11:27:44.388Z","iobWithZeroTemp":{"iob":-0.285,"basaliob":-0.285,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.388Z"}},{"iob":0.119,"basaliob":0.119,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T11:32:44.388Z","iobWithZeroTemp":{"iob":-0.311,"basaliob":-0.311,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:44.388Z"}},{"iob":0.11,"basaliob":0.11,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T11:37:44.388Z","iobWithZeroTemp":{"iob":-0.334,"basaliob":-0.334,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:44.388Z"}},{"iob":0.101,"basaliob":0.101,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T11:42:44.388Z","iobWithZeroTemp":{"iob":-0.357,"basaliob":-0.357,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:44.388Z"}},{"iob":0.093,"basaliob":0.093,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:47:44.388Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:44.388Z"}},{"iob":0.085,"basaliob":0.085,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T11:52:44.388Z","iobWithZeroTemp":{"iob":-0.399,"basaliob":-0.399,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:44.388Z"}},{"iob":0.078,"basaliob":0.078,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:57:44.388Z","iobWithZeroTemp":{"iob":-0.417,"basaliob":-0.417,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:44.388Z"}},{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T12:02:44.388Z","iobWithZeroTemp":{"iob":-0.434,"basaliob":-0.434,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:44.388Z"}},{"iob":0.065,"basaliob":0.065,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T12:07:44.388Z","iobWithZeroTemp":{"iob":-0.451,"basaliob":-0.451,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:44.388Z"}},{"iob":0.06,"basaliob":0.06,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T12:12:44.388Z","iobWithZeroTemp":{"iob":-0.465,"basaliob":-0.465,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:44.388Z"}},{"iob":0.055,"basaliob":0.055,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T12:17:44.388Z","iobWithZeroTemp":{"iob":-0.478,"basaliob":-0.478,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:44.388Z"}},{"iob":0.05,"basaliob":0.05,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:44.388Z","iobWithZeroTemp":{"iob":-0.491,"basaliob":-0.491,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:44.388Z"}},{"iob":0.045,"basaliob":0.045,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:44.388Z","iobWithZeroTemp":{"iob":-0.504,"basaliob":-0.504,"bolussnooze":0,"activity":-0.0038,"lastBolusTime":0,"time":"2024-01-05T12:27:44.388Z"}},{"iob":0.041,"basaliob":0.041,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:44.388Z","iobWithZeroTemp":{"iob":-0.515,"basaliob":-0.515,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:44.388Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:44.388Z","iobWithZeroTemp":{"iob":-0.525,"basaliob":-0.525,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:44.388Z"}},{"iob":0.034,"basaliob":0.034,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:44.388Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:44.388Z"}},{"iob":0.031,"basaliob":0.031,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:44.388Z","iobWithZeroTemp":{"iob":-0.543,"basaliob":-0.543,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:44.388Z"}},{"iob":0.028,"basaliob":0.028,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:44.388Z","iobWithZeroTemp":{"iob":-0.551,"basaliob":-0.551,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:44.388Z"}},{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:44.388Z","iobWithZeroTemp":{"iob":-0.558,"basaliob":-0.558,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T12:57:44.388Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:44.388Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:02:44.388Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:44.388Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:07:44.388Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:44.388Z","iobWithZeroTemp":{"iob":-0.577,"basaliob":-0.577,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:44.388Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:44.388Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:17:44.388Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:44.388Z","iobWithZeroTemp":{"iob":-0.587,"basaliob":-0.587,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:22:44.388Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:44.388Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:44.388Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:44.388Z","iobWithZeroTemp":{"iob":-0.596,"basaliob":-0.596,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:44.388Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:44.388Z","iobWithZeroTemp":{"iob":-0.599,"basaliob":-0.599,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:44.388Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:44.388Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:44.388Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:44.388Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:44.388Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:44.388Z","iobWithZeroTemp":{"iob":-0.608,"basaliob":-0.608,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:52:44.388Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:44.388Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:44.388Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5, "autoISF_min":0.4, + "bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-2.8663636363636362,"slopeFromMinDeviation":1.8164999999999996,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704448967353,"flatBGsDetected":false},"output":{"temp":"absolute","bg":129,"tick":-12,"eventualBG":31,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:02:47.353Z","sensitivityRatio":1,"variable_sens":131.2,"predBGs":{"IOB":[129,118,108,98,90,82,75,69,63,59,55,53,51,49,47,45,44,42,41,40,39],"ZT":[129,126,123,120,117,114,112,110,108,106,104,103,103,102,101,101,101,102,102]},"COB":0,"IOB":0.427,"reason":"COB: 0, Dev: -42, BGI: -3, ISF: 131, CR: 17.3, Target: 91, minPredBG 70, minGuardBG 25, IOBpredBG 39; minGuardBG 25<66","duration":90,"rate":0,"timestamp":"2024-01-05T10:02:47.392Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_110747.json b/app/src/androidTest/assets/results/2024-01-05_110747.json new file mode 100644 index 00000000000..1682f6ac81d --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_110747.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":105,"noise":0,"delta":-19.39,"short_avgdelta":-19.39,"long_avgdelta":-13.34,"date":1704449100000,"dura_ISF_minutes":0,"dura_ISF_average":105,"parabola_fit_correlation":0.9974,"parabola_fit_minutes":15,"parabola_fit_last_delta":-22.40000000000009,"parabola_fit_next_delta":-29.400000000000333,"parabola_fit_a0":105.4,"parabola_fit_a1":-25.9,"parabola_fit_a2":-3.5,"bg_acceleration":-7.0000000000002425},"currenttemp":{"temp":"absolute","duration":70,"rate":0,"minutesrunning":20},"iob_data":[{"iob":0.372,"basaliob":0.372,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2024-01-05T10:07:44.190Z","iobWithZeroTemp":{"iob":0.372,"basaliob":0.372,"bolussnooze":0,"activity":0.0048,"lastBolusTime":0,"time":"2024-01-05T10:07:44.190Z"}},{"iob":0.348,"basaliob":0.348,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2024-01-05T10:12:44.190Z","iobWithZeroTemp":{"iob":0.323,"basaliob":0.323,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2024-01-05T10:12:44.190Z"}},{"iob":0.326,"basaliob":0.326,"bolussnooze":0,"activity":0.0044,"lastBolusTime":0,"time":"2024-01-05T10:17:44.190Z","iobWithZeroTemp":{"iob":0.271,"basaliob":0.271,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:44.190Z"}},{"iob":0.305,"basaliob":0.305,"bolussnooze":0,"activity":0.0042,"lastBolusTime":0,"time":"2024-01-05T10:22:44.190Z","iobWithZeroTemp":{"iob":0.22,"basaliob":0.22,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:44.190Z"}},{"iob":0.284,"basaliob":0.284,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:27:44.190Z","iobWithZeroTemp":{"iob":0.169,"basaliob":0.169,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2024-01-05T10:27:44.190Z"}},{"iob":0.265,"basaliob":0.265,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2024-01-05T10:32:44.190Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:44.190Z"}},{"iob":0.247,"basaliob":0.247,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:37:44.190Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:37:44.190Z"}},{"iob":0.229,"basaliob":0.229,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2024-01-05T10:42:44.190Z","iobWithZeroTemp":{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:42:44.190Z"}},{"iob":0.213,"basaliob":0.213,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2024-01-05T10:47:44.190Z","iobWithZeroTemp":{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:47:44.190Z"}},{"iob":0.197,"basaliob":0.197,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:52:44.190Z","iobWithZeroTemp":{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:44.190Z"}},{"iob":0.183,"basaliob":0.183,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2024-01-05T10:57:44.190Z","iobWithZeroTemp":{"iob":-0.092,"basaliob":-0.092,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T10:57:44.190Z"}},{"iob":0.169,"basaliob":0.169,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T11:02:44.190Z","iobWithZeroTemp":{"iob":-0.129,"basaliob":-0.129,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:02:44.190Z"}},{"iob":0.156,"basaliob":0.156,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T11:07:44.190Z","iobWithZeroTemp":{"iob":-0.164,"basaliob":-0.164,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.190Z"}},{"iob":0.144,"basaliob":0.144,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2024-01-05T11:12:44.190Z","iobWithZeroTemp":{"iob":-0.197,"basaliob":-0.197,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.190Z"}},{"iob":0.133,"basaliob":0.133,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T11:17:44.190Z","iobWithZeroTemp":{"iob":-0.228,"basaliob":-0.228,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.190Z"}},{"iob":0.123,"basaliob":0.123,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T11:22:44.190Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.190Z"}},{"iob":0.113,"basaliob":0.113,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2024-01-05T11:27:44.190Z","iobWithZeroTemp":{"iob":-0.284,"basaliob":-0.284,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.190Z"}},{"iob":0.104,"basaliob":0.104,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T11:32:44.190Z","iobWithZeroTemp":{"iob":-0.31,"basaliob":-0.31,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:44.190Z"}},{"iob":0.095,"basaliob":0.095,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:37:44.190Z","iobWithZeroTemp":{"iob":-0.335,"basaliob":-0.335,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:44.190Z"}},{"iob":0.087,"basaliob":0.087,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T11:42:44.190Z","iobWithZeroTemp":{"iob":-0.357,"basaliob":-0.357,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:44.190Z"}},{"iob":0.08,"basaliob":0.08,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:47:44.190Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2024-01-05T11:47:44.190Z"}},{"iob":0.073,"basaliob":0.073,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:52:44.190Z","iobWithZeroTemp":{"iob":-0.398,"basaliob":-0.398,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:44.190Z"}},{"iob":0.067,"basaliob":0.067,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:57:44.190Z","iobWithZeroTemp":{"iob":-0.417,"basaliob":-0.417,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:44.190Z"}},{"iob":0.061,"basaliob":0.061,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T12:02:44.190Z","iobWithZeroTemp":{"iob":-0.434,"basaliob":-0.434,"bolussnooze":0,"activity":-0.0029,"lastBolusTime":0,"time":"2024-01-05T12:02:44.190Z"}},{"iob":0.056,"basaliob":0.056,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T12:07:44.190Z","iobWithZeroTemp":{"iob":-0.45,"basaliob":-0.45,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:44.190Z"}},{"iob":0.051,"basaliob":0.051,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T12:12:44.190Z","iobWithZeroTemp":{"iob":-0.465,"basaliob":-0.465,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:44.190Z"}},{"iob":0.046,"basaliob":0.046,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:44.190Z","iobWithZeroTemp":{"iob":-0.479,"basaliob":-0.479,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:44.190Z"}},{"iob":0.042,"basaliob":0.042,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:44.190Z","iobWithZeroTemp":{"iob":-0.491,"basaliob":-0.491,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:44.190Z"}},{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:44.190Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:44.190Z"}},{"iob":0.034,"basaliob":0.034,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:44.190Z","iobWithZeroTemp":{"iob":-0.515,"basaliob":-0.515,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:44.190Z"}},{"iob":0.031,"basaliob":0.031,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:44.190Z","iobWithZeroTemp":{"iob":-0.525,"basaliob":-0.525,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:44.190Z"}},{"iob":0.028,"basaliob":0.028,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:44.190Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:44.190Z"}},{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:44.190Z","iobWithZeroTemp":{"iob":-0.543,"basaliob":-0.543,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:44.190Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:44.190Z","iobWithZeroTemp":{"iob":-0.551,"basaliob":-0.551,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:44.190Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:44.190Z","iobWithZeroTemp":{"iob":-0.559,"basaliob":-0.559,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T12:57:44.190Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:44.190Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:02:44.190Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:44.190Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:07:44.190Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:44.190Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:44.190Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:44.190Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:17:44.190Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:44.190Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:22:44.190Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:44.190Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:27:44.190Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:44.190Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:44.190Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:44.190Z","iobWithZeroTemp":{"iob":-0.599,"basaliob":-0.599,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:44.190Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:44.190Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:42:44.190Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:44.190Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:44.190Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:44.190Z","iobWithZeroTemp":{"iob":-0.608,"basaliob":-0.608,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:52:44.190Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:44.190Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:44.190Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:44.190Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:02:44.190Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-2.9733636363636364,"slopeFromMinDeviation":0,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704449267242,"flatBGsDetected":false},"output":{"temp":"absolute","bg":105,"tick":-19,"eventualBG":-43,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:07:47.242Z","sensitivityRatio":1,"variable_sens":295,"predBGs":{"IOB":[105,87,70,54,40,39,39,39,39,39,39,39,39],"ZT":[105,98,91,85,79,73,69,64,60,57,54,53,51,50,50,50,51,52,54,56,59,62,65,69,73,78,83,88]},"COB":0,"IOB":0.372,"reason":"COB: 0, Dev: -38, BGI: -7, ISF: 295, CR: 17.3, Target: 91, minPredBG 45, minGuardBG -75, IOBpredBG 39; 7 add'l carbs req w\/in 15m; minGuardBG -75<66","carbsReq":7,"carbsReqWithin":15,"duration":90,"rate":0,"timestamp":"2024-01-05T10:07:47.264Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_111248.json b/app/src/androidTest/assets/results/2024-01-05_111248.json new file mode 100644 index 00000000000..3170f55aceb --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_111248.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":95,"noise":0,"delta":-14.22,"short_avgdelta":-14.22,"long_avgdelta":-13.61,"date":1704449400000,"dura_ISF_minutes":0,"dura_ISF_average":95,"parabola_fit_correlation":0.9904,"parabola_fit_minutes":35,"parabola_fit_last_delta":-14.952380952381061,"parabola_fit_next_delta":-15.190476190476303,"parabola_fit_a0":94.6,"parabola_fit_a1":-15.07,"parabola_fit_a2":-0.12,"bg_acceleration":-0.23809523809524066},"currenttemp":{"temp":"absolute","duration":65,"rate":0,"minutesrunning":25},"iob_data":[{"iob":0.318,"basaliob":0.318,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2024-01-05T10:12:44.617Z","iobWithZeroTemp":{"iob":0.318,"basaliob":0.318,"bolussnooze":0,"activity":0.0046,"lastBolusTime":0,"time":"2024-01-05T10:12:44.617Z"}},{"iob":0.295,"basaliob":0.295,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:44.617Z","iobWithZeroTemp":{"iob":0.27,"basaliob":0.27,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:44.617Z"}},{"iob":0.274,"basaliob":0.274,"bolussnooze":0,"activity":0.0041,"lastBolusTime":0,"time":"2024-01-05T10:22:44.617Z","iobWithZeroTemp":{"iob":0.219,"basaliob":0.219,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:44.617Z"}},{"iob":0.255,"basaliob":0.255,"bolussnooze":0,"activity":0.0038,"lastBolusTime":0,"time":"2024-01-05T10:27:44.617Z","iobWithZeroTemp":{"iob":0.17,"basaliob":0.17,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:27:44.617Z"}},{"iob":0.236,"basaliob":0.236,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:32:44.617Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:44.617Z"}},{"iob":0.219,"basaliob":0.219,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2024-01-05T10:37:44.617Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:44.617Z"}},{"iob":0.202,"basaliob":0.202,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2024-01-05T10:42:44.617Z","iobWithZeroTemp":{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:42:44.617Z"}},{"iob":0.187,"basaliob":0.187,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:47:44.617Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:47:44.617Z"}},{"iob":0.172,"basaliob":0.172,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2024-01-05T10:52:44.617Z","iobWithZeroTemp":{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:44.617Z"}},{"iob":0.159,"basaliob":0.159,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:57:44.617Z","iobWithZeroTemp":{"iob":-0.092,"basaliob":-0.092,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:44.617Z"}},{"iob":0.146,"basaliob":0.146,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-05T11:02:44.617Z","iobWithZeroTemp":{"iob":-0.129,"basaliob":-0.129,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:02:44.617Z"}},{"iob":0.135,"basaliob":0.135,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2024-01-05T11:07:44.617Z","iobWithZeroTemp":{"iob":-0.163,"basaliob":-0.163,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.617Z"}},{"iob":0.124,"basaliob":0.124,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T11:12:44.617Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.617Z"}},{"iob":0.114,"basaliob":0.114,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T11:17:44.617Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.617Z"}},{"iob":0.104,"basaliob":0.104,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T11:22:44.617Z","iobWithZeroTemp":{"iob":-0.257,"basaliob":-0.257,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.617Z"}},{"iob":0.095,"basaliob":0.095,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T11:27:44.617Z","iobWithZeroTemp":{"iob":-0.284,"basaliob":-0.284,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.617Z"}},{"iob":0.087,"basaliob":0.087,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:32:44.617Z","iobWithZeroTemp":{"iob":-0.31,"basaliob":-0.31,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:44.617Z"}},{"iob":0.08,"basaliob":0.08,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:37:44.617Z","iobWithZeroTemp":{"iob":-0.334,"basaliob":-0.334,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:44.617Z"}},{"iob":0.073,"basaliob":0.073,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:42:44.617Z","iobWithZeroTemp":{"iob":-0.357,"basaliob":-0.357,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:44.617Z"}},{"iob":0.066,"basaliob":0.066,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:47:44.617Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2024-01-05T11:47:44.617Z"}},{"iob":0.06,"basaliob":0.06,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:52:44.617Z","iobWithZeroTemp":{"iob":-0.398,"basaliob":-0.398,"bolussnooze":0,"activity":-0.0024,"lastBolusTime":0,"time":"2024-01-05T11:52:44.617Z"}},{"iob":0.055,"basaliob":0.055,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:57:44.617Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2024-01-05T11:57:44.617Z"}},{"iob":0.05,"basaliob":0.05,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T12:02:44.617Z","iobWithZeroTemp":{"iob":-0.434,"basaliob":-0.434,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:44.617Z"}},{"iob":0.045,"basaliob":0.045,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:44.617Z","iobWithZeroTemp":{"iob":-0.45,"basaliob":-0.45,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:44.617Z"}},{"iob":0.041,"basaliob":0.041,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:44.617Z","iobWithZeroTemp":{"iob":-0.465,"basaliob":-0.465,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:44.617Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:44.617Z","iobWithZeroTemp":{"iob":-0.479,"basaliob":-0.479,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:44.617Z"}},{"iob":0.033,"basaliob":0.033,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:44.617Z","iobWithZeroTemp":{"iob":-0.492,"basaliob":-0.492,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:44.617Z"}},{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:44.617Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:44.617Z"}},{"iob":0.027,"basaliob":0.027,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:44.617Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:44.617Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:44.617Z","iobWithZeroTemp":{"iob":-0.525,"basaliob":-0.525,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:44.617Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:44.617Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:44.617Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:44.617Z","iobWithZeroTemp":{"iob":-0.543,"basaliob":-0.543,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:44.617Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:44.617Z","iobWithZeroTemp":{"iob":-0.551,"basaliob":-0.551,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:44.617Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:44.617Z","iobWithZeroTemp":{"iob":-0.559,"basaliob":-0.559,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:44.617Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:44.617Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:02:44.617Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:44.617Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:07:44.617Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:44.617Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:44.617Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:44.617Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:17:44.617Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:44.617Z","iobWithZeroTemp":{"iob":-0.587,"basaliob":-0.587,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:22:44.617Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:44.617Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:44.617Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:44.617Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:44.617Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:44.617Z","iobWithZeroTemp":{"iob":-0.599,"basaliob":-0.599,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:37:44.617Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:44.617Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:44.617Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:44.617Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:44.617Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:44.617Z","iobWithZeroTemp":{"iob":-0.608,"basaliob":-0.608,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:52:44.617Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:44.617Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:44.617Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:44.617Z","iobWithZeroTemp":{"iob":-0.613,"basaliob":-0.613,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T14:02:44.617Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:44.617Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:44.617Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-2.727272727272727,"slopeFromMinDeviation":0,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704449567717,"flatBGsDetected":false},"output":{"temp":"absolute","bg":95,"tick":-14,"eventualBG":-13,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:12:47.717Z","sensitivityRatio":1,"variable_sens":144.1,"predBGs":{"IOB":[95,82,70,58,48,39,39,39,39,39,39,39,39],"ZT":[95,92,89,86,83,81,79,77,75,74,73,72,72,72,72,72,73,73,75,76,77,79,81,83,85,88,90]},"COB":0,"IOB":0.318,"reason":"COB: 0, Dev: -62, BGI: -3, ISF: 144, CR: 17.3, Target: 91, minPredBG 51, minGuardBG -12, IOBpredBG 39; minGuardBG -12<66","duration":120,"rate":0,"timestamp":"2024-01-05T10:12:47.745Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_111747.json b/app/src/androidTest/assets/results/2024-01-05_111747.json new file mode 100644 index 00000000000..a3693e97de5 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_111747.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":90,"noise":0,"delta":-8.5,"short_avgdelta":-8.5,"long_avgdelta":-12.73,"date":1704449700000,"dura_ISF_minutes":0,"dura_ISF_average":90,"parabola_fit_correlation":0.9955,"parabola_fit_minutes":15,"parabola_fit_last_delta":-3.2000000000001805,"parabola_fit_next_delta":6.299999999999706,"parabola_fit_a0":90.5,"parabola_fit_a1":1.55,"parabola_fit_a2":4.75,"bg_acceleration":9.499999999999886},"currenttemp":{"temp":"absolute","duration":115,"rate":0,"minutesrunning":5},"iob_data":[{"iob":0.265,"basaliob":0.265,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:43.938Z","iobWithZeroTemp":{"iob":0.265,"basaliob":0.265,"bolussnooze":0,"activity":0.0043,"lastBolusTime":0,"time":"2024-01-05T10:17:43.938Z"}},{"iob":0.244,"basaliob":0.244,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:43.938Z","iobWithZeroTemp":{"iob":0.219,"basaliob":0.219,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:43.938Z"}},{"iob":0.225,"basaliob":0.225,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2024-01-05T10:27:43.938Z","iobWithZeroTemp":{"iob":0.17,"basaliob":0.17,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:27:43.938Z"}},{"iob":0.207,"basaliob":0.207,"bolussnooze":0,"activity":0.0035,"lastBolusTime":0,"time":"2024-01-05T10:32:43.938Z","iobWithZeroTemp":{"iob":0.122,"basaliob":0.122,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:43.938Z"}},{"iob":0.19,"basaliob":0.19,"bolussnooze":0,"activity":0.0032,"lastBolusTime":0,"time":"2024-01-05T10:37:43.938Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:43.938Z"}},{"iob":0.174,"basaliob":0.174,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:42:43.938Z","iobWithZeroTemp":{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:43.938Z"}},{"iob":0.16,"basaliob":0.16,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2024-01-05T10:47:43.938Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:47:43.938Z"}},{"iob":0.146,"basaliob":0.146,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:52:43.938Z","iobWithZeroTemp":{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:43.938Z"}},{"iob":0.134,"basaliob":0.134,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-05T10:57:43.938Z","iobWithZeroTemp":{"iob":-0.092,"basaliob":-0.092,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:43.938Z"}},{"iob":0.122,"basaliob":0.122,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T11:02:43.938Z","iobWithZeroTemp":{"iob":-0.129,"basaliob":-0.129,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:43.938Z"}},{"iob":0.112,"basaliob":0.112,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T11:07:43.938Z","iobWithZeroTemp":{"iob":-0.163,"basaliob":-0.163,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:43.938Z"}},{"iob":0.102,"basaliob":0.102,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2024-01-05T11:12:43.938Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:43.938Z"}},{"iob":0.093,"basaliob":0.093,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T11:17:43.938Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:43.938Z"}},{"iob":0.085,"basaliob":0.085,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:22:43.938Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:43.938Z"}},{"iob":0.077,"basaliob":0.077,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T11:27:43.938Z","iobWithZeroTemp":{"iob":-0.284,"basaliob":-0.284,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:43.938Z"}},{"iob":0.07,"basaliob":0.07,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:32:43.938Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:43.938Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:37:43.938Z","iobWithZeroTemp":{"iob":-0.334,"basaliob":-0.334,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2024-01-05T11:37:43.938Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:42:43.938Z","iobWithZeroTemp":{"iob":-0.357,"basaliob":-0.357,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:43.938Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:47:43.938Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:43.938Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:52:43.938Z","iobWithZeroTemp":{"iob":-0.397,"basaliob":-0.397,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:43.938Z"}},{"iob":0.042,"basaliob":0.042,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:43.938Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:43.938Z"}},{"iob":0.038,"basaliob":0.038,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:43.938Z","iobWithZeroTemp":{"iob":-0.433,"basaliob":-0.433,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:43.938Z"}},{"iob":0.034,"basaliob":0.034,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:43.938Z","iobWithZeroTemp":{"iob":-0.45,"basaliob":-0.45,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:43.938Z"}},{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:43.938Z","iobWithZeroTemp":{"iob":-0.465,"basaliob":-0.465,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:43.938Z"}},{"iob":0.027,"basaliob":0.027,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:43.938Z","iobWithZeroTemp":{"iob":-0.479,"basaliob":-0.479,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:43.938Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:43.938Z","iobWithZeroTemp":{"iob":-0.492,"basaliob":-0.492,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:43.938Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:43.938Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:43.938Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:43.938Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:43.938Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:43.938Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:43.938Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:43.938Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:43.938Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:43.938Z","iobWithZeroTemp":{"iob":-0.543,"basaliob":-0.543,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:43.938Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:43.938Z","iobWithZeroTemp":{"iob":-0.55,"basaliob":-0.55,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:43.938Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:43.938Z","iobWithZeroTemp":{"iob":-0.558,"basaliob":-0.558,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:43.938Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:43.938Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:02:43.938Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:43.938Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:07:43.938Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:43.938Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:43.938Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:43.938Z","iobWithZeroTemp":{"iob":-0.581,"basaliob":-0.581,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:17:43.938Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:43.938Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:22:43.938Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:43.938Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:27:43.938Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:43.938Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:43.938Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:43.938Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:43.938Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:43.938Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:42:43.938Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:43.938Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:43.938Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:43.938Z","iobWithZeroTemp":{"iob":-0.608,"basaliob":-0.608,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:52:43.938Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:43.938Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:43.938Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:43.938Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T14:02:43.938Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:07:43.938Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:43.938Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:12:43.938Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:12:43.938Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-1.7592727272727273,"slopeFromMinDeviation":2.49,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704449867075,"flatBGsDetected":false},"output":{"temp":"absolute","bg":90,"tick":-8,"eventualBG":0,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:17:47.075Z","sensitivityRatio":1,"variable_sens":100.1,"predBGs":{"IOB":[90,82,75,68,62,57,52,48,45,42,40,39,39],"ZT":[90,88,86,84,82,81,80,79,78,77,76,76,76,76,76,77,77,78,79,80,81,83,84,85,87,89,91]},"COB":0,"IOB":0.265,"reason":"COB: 0, Dev: -63, BGI: -2, ISF: 100, CR: 17.3, Target: 91, minPredBG 50, minGuardBG 28, IOBpredBG 39; minGuardBG 28<66 115m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:17:47.108Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_112247.json b/app/src/androidTest/assets/results/2024-01-05_112247.json new file mode 100644 index 00000000000..74bfd24cbb3 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_112247.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":86,"noise":0,"delta":-4.94,"short_avgdelta":-4.94,"long_avgdelta":-11.14,"date":1704450000000,"dura_ISF_minutes":5,"dura_ISF_average":88,"parabola_fit_correlation":0.996,"parabola_fit_minutes":15,"parabola_fit_last_delta":-3.2000000000000917,"parabola_fit_next_delta":-0.19999999999997797,"parabola_fit_a0":86.2,"parabola_fit_a1":-1.7,"parabola_fit_a2":1.5,"bg_acceleration":3.0000000000001137},"currenttemp":{"temp":"absolute","duration":110,"rate":0,"minutesrunning":10},"iob_data":[{"iob":0.213,"basaliob":0.213,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:43.399Z","iobWithZeroTemp":{"iob":0.213,"basaliob":0.213,"bolussnooze":0,"activity":0.004,"lastBolusTime":0,"time":"2024-01-05T10:22:43.399Z"}},{"iob":0.194,"basaliob":0.194,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2024-01-05T10:27:43.399Z","iobWithZeroTemp":{"iob":0.169,"basaliob":0.169,"bolussnooze":0,"activity":0.0037,"lastBolusTime":0,"time":"2024-01-05T10:27:43.399Z"}},{"iob":0.176,"basaliob":0.176,"bolussnooze":0,"activity":0.0034,"lastBolusTime":0,"time":"2024-01-05T10:32:43.399Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:43.399Z"}},{"iob":0.16,"basaliob":0.16,"bolussnooze":0,"activity":0.0031,"lastBolusTime":0,"time":"2024-01-05T10:37:43.399Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:43.399Z"}},{"iob":0.145,"basaliob":0.145,"bolussnooze":0,"activity":0.0028,"lastBolusTime":0,"time":"2024-01-05T10:42:43.399Z","iobWithZeroTemp":{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:43.399Z"}},{"iob":0.132,"basaliob":0.132,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:47:43.399Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:43.399Z"}},{"iob":0.119,"basaliob":0.119,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-05T10:52:43.399Z","iobWithZeroTemp":{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:43.399Z"}},{"iob":0.108,"basaliob":0.108,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:57:43.399Z","iobWithZeroTemp":{"iob":-0.091,"basaliob":-0.091,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:43.399Z"}},{"iob":0.097,"basaliob":0.097,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T11:02:43.399Z","iobWithZeroTemp":{"iob":-0.129,"basaliob":-0.129,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:43.399Z"}},{"iob":0.088,"basaliob":0.088,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T11:07:43.399Z","iobWithZeroTemp":{"iob":-0.163,"basaliob":-0.163,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:43.399Z"}},{"iob":0.079,"basaliob":0.079,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T11:12:43.399Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:43.399Z"}},{"iob":0.071,"basaliob":0.071,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T11:17:43.399Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:43.399Z"}},{"iob":0.064,"basaliob":0.064,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:22:43.399Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:43.399Z"}},{"iob":0.057,"basaliob":0.057,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:27:43.399Z","iobWithZeroTemp":{"iob":-0.284,"basaliob":-0.284,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:43.399Z"}},{"iob":0.051,"basaliob":0.051,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:32:43.399Z","iobWithZeroTemp":{"iob":-0.31,"basaliob":-0.31,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:43.399Z"}},{"iob":0.046,"basaliob":0.046,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:37:43.399Z","iobWithZeroTemp":{"iob":-0.333,"basaliob":-0.333,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2024-01-05T11:37:43.399Z"}},{"iob":0.041,"basaliob":0.041,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:42:43.399Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2024-01-05T11:42:43.399Z"}},{"iob":0.036,"basaliob":0.036,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:43.399Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:43.399Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:43.399Z","iobWithZeroTemp":{"iob":-0.398,"basaliob":-0.398,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:43.399Z"}},{"iob":0.028,"basaliob":0.028,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:43.399Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:43.399Z"}},{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:43.399Z","iobWithZeroTemp":{"iob":-0.433,"basaliob":-0.433,"bolussnooze":0,"activity":-0.0029,"lastBolusTime":0,"time":"2024-01-05T12:02:43.399Z"}},{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:43.399Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.003,"lastBolusTime":0,"time":"2024-01-05T12:07:43.399Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:43.399Z","iobWithZeroTemp":{"iob":-0.465,"basaliob":-0.465,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:43.399Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:43.399Z","iobWithZeroTemp":{"iob":-0.478,"basaliob":-0.478,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:43.399Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:43.399Z","iobWithZeroTemp":{"iob":-0.492,"basaliob":-0.492,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:43.399Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:43.399Z","iobWithZeroTemp":{"iob":-0.504,"basaliob":-0.504,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:43.399Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:43.399Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.0041,"lastBolusTime":0,"time":"2024-01-05T12:32:43.399Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:43.399Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:43.399Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:43.399Z","iobWithZeroTemp":{"iob":-0.533,"basaliob":-0.533,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:43.399Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:43.399Z","iobWithZeroTemp":{"iob":-0.543,"basaliob":-0.543,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:43.399Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:43.399Z","iobWithZeroTemp":{"iob":-0.551,"basaliob":-0.551,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:43.399Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:43.399Z","iobWithZeroTemp":{"iob":-0.558,"basaliob":-0.558,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:43.399Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:43.399Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T13:02:43.399Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:43.399Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:07:43.399Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:43.399Z","iobWithZeroTemp":{"iob":-0.577,"basaliob":-0.577,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:43.399Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:43.399Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:17:43.399Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:43.399Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:22:43.399Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:43.399Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:43.399Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:43.399Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:43.399Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:43.399Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:37:43.399Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:42:43.399Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:47:43.399Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:52:43.399Z","iobWithZeroTemp":{"iob":-0.608,"basaliob":-0.608,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:52:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:57:43.399Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:02:43.399Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:02:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:07:43.399Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:12:43.399Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:12:43.399Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:17:43.399Z","iobWithZeroTemp":{"iob":-0.617,"basaliob":-0.617,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:17:43.399Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-1.0586363636363636,"slopeFromMinDeviation":4.5195,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704450166692,"flatBGsDetected":false},"output":{"temp":"absolute","bg":86,"tick":-5,"eventualBG":-2,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:22:46.692Z","sensitivityRatio":1,"variable_sens":218.8,"predBGs":{"IOB":[86,81,77,72,69,65,62,59,57,54,52,50,49,47,46,44,43,42,41,40,39],"ZT":[86,82,78,74,71,68,66,64,62,61,61,60,61,61,62,63,65,67,69,71,74,77,81,84,88]},"COB":0,"IOB":0.213,"reason":"COB: 0, Dev: -41, BGI: -4, ISF: 219, CR: 17.3, Target: 91, minPredBG 50, minGuardBG 33, IOBpredBG 39; minGuardBG 33<66 110m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:22:46.719Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_112745.json b/app/src/androidTest/assets/results/2024-01-05_112745.json new file mode 100644 index 00000000000..fdb0a89b692 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_112745.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":78,"noise":0,"delta":-6.56,"short_avgdelta":-6.56,"long_avgdelta":-9.74,"date":1704450300000,"dura_ISF_minutes":0,"dura_ISF_average":78,"parabola_fit_correlation":0.9919,"parabola_fit_minutes":15,"parabola_fit_last_delta":-6.999999999999814,"parabola_fit_next_delta":-8.499999999999872,"parabola_fit_a0":78.2,"parabola_fit_a1":-7.75,"parabola_fit_a2":-0.75,"bg_acceleration":-1.5000000000000568},"currenttemp":{"temp":"absolute","duration":105,"rate":0,"minutesrunning":15},"iob_data":[{"iob":0.163,"basaliob":0.163,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:27:42.183Z","iobWithZeroTemp":{"iob":0.163,"basaliob":0.163,"bolussnooze":0,"activity":0.0036,"lastBolusTime":0,"time":"2024-01-05T10:27:42.183Z"}},{"iob":0.146,"basaliob":0.146,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:42.183Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:42.183Z"}},{"iob":0.13,"basaliob":0.13,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-05T10:37:42.183Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:42.183Z"}},{"iob":0.116,"basaliob":0.116,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-05T10:42:42.183Z","iobWithZeroTemp":{"iob":0.031,"basaliob":0.031,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:42.183Z"}},{"iob":0.103,"basaliob":0.103,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-05T10:47:42.183Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:42.183Z"}},{"iob":0.092,"basaliob":0.092,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:52:42.183Z","iobWithZeroTemp":{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:42.183Z"}},{"iob":0.081,"basaliob":0.081,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-05T10:57:42.183Z","iobWithZeroTemp":{"iob":-0.091,"basaliob":-0.091,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:42.183Z"}},{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T11:02:42.183Z","iobWithZeroTemp":{"iob":-0.127,"basaliob":-0.127,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:42.183Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:07:42.183Z","iobWithZeroTemp":{"iob":-0.163,"basaliob":-0.163,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:42.183Z"}},{"iob":0.055,"basaliob":0.055,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T11:12:42.183Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:42.183Z"}},{"iob":0.048,"basaliob":0.048,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:17:42.183Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:42.183Z"}},{"iob":0.042,"basaliob":0.042,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:22:42.183Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:42.183Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:27:42.183Z","iobWithZeroTemp":{"iob":-0.283,"basaliob":-0.283,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:42.183Z"}},{"iob":0.032,"basaliob":0.032,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:42.183Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2024-01-05T11:32:42.183Z"}},{"iob":0.027,"basaliob":0.027,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:37:42.183Z","iobWithZeroTemp":{"iob":-0.334,"basaliob":-0.334,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:42.183Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:42.183Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2024-01-05T11:42:42.183Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:42.183Z","iobWithZeroTemp":{"iob":-0.377,"basaliob":-0.377,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:42.183Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:42.183Z","iobWithZeroTemp":{"iob":-0.398,"basaliob":-0.398,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:42.183Z"}},{"iob":0.014,"basaliob":0.014,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:42.183Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:42.183Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:42.183Z","iobWithZeroTemp":{"iob":-0.433,"basaliob":-0.433,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:42.183Z"}},{"iob":0.009,"basaliob":0.009,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:42.183Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:42.183Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:42.183Z","iobWithZeroTemp":{"iob":-0.464,"basaliob":-0.464,"bolussnooze":0,"activity":-0.0032,"lastBolusTime":0,"time":"2024-01-05T12:12:42.183Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:42.183Z","iobWithZeroTemp":{"iob":-0.479,"basaliob":-0.479,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:42.183Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:42.183Z","iobWithZeroTemp":{"iob":-0.491,"basaliob":-0.491,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:42.183Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:42.183Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:42.183Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:42.183Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.0041,"lastBolusTime":0,"time":"2024-01-05T12:32:42.183Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:42.183Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:42.183Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:42.183Z","iobWithZeroTemp":{"iob":-0.533,"basaliob":-0.533,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:42:42.183Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:42.183Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:42.183Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:42.183Z","iobWithZeroTemp":{"iob":-0.551,"basaliob":-0.551,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:42.183Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:42.183Z","iobWithZeroTemp":{"iob":-0.558,"basaliob":-0.558,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:42.183Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:42.183Z","iobWithZeroTemp":{"iob":-0.564,"basaliob":-0.564,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T13:02:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:42.183Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:07:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:12:42.183Z","iobWithZeroTemp":{"iob":-0.577,"basaliob":-0.577,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:12:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:17:42.183Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:17:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:22:42.183Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:22:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:27:42.183Z","iobWithZeroTemp":{"iob":-0.59,"basaliob":-0.59,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:27:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:32:42.183Z","iobWithZeroTemp":{"iob":-0.594,"basaliob":-0.594,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:37:42.183Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:42:42.183Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:42:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:47:42.183Z","iobWithZeroTemp":{"iob":-0.604,"basaliob":-0.604,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:52:42.183Z","iobWithZeroTemp":{"iob":-0.607,"basaliob":-0.607,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:52:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:57:42.183Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:02:42.183Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T14:02:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:07:42.183Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:12:42.183Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:12:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:17:42.183Z","iobWithZeroTemp":{"iob":-0.618,"basaliob":-0.618,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:17:42.183Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T14:22:42.183Z","iobWithZeroTemp":{"iob":-0.619,"basaliob":-0.619,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:22:42.183Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-1.0449,"slopeFromMinDeviation":3.156333333333334,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704450465186,"flatBGsDetected":false},"output":{"temp":"absolute","bg":78,"tick":-7,"eventualBG":7,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:27:45.186Z","sensitivityRatio":1,"variable_sens":235.2,"predBGs":{"IOB":[78,72,66,61,56,52,48,45,42,39,39,39,39],"ZT":[78,74,70,66,64,61,59,57,56,56,55,55,56,57,58,60,62,64,67,70,74,77,81,85,89]},"COB":0,"IOB":0.163,"reason":"COB: 0, Dev: -33, BGI: -4, ISF: 235, CR: 17.3, Target: 91, minPredBG 47, minGuardBG 24, IOBpredBG 39; minGuardBG 24<66 105m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:27:45.222Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_113245.json b/app/src/androidTest/assets/results/2024-01-05_113245.json new file mode 100644 index 00000000000..847879f701f --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_113245.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":82,"noise":0,"delta":-0.22,"short_avgdelta":-0.22,"long_avgdelta":-6.6,"date":1704450600000,"dura_ISF_minutes":5,"dura_ISF_average":80,"parabola_fit_correlation":0.9832,"parabola_fit_minutes":35,"parabola_fit_last_delta":1.1190476190476841,"parabola_fit_next_delta":4.41666666666671,"parabola_fit_a0":81.7,"parabola_fit_a1":2.77,"parabola_fit_a2":1.65,"bg_acceleration":3.2976190476190257},"currenttemp":{"temp":"absolute","duration":100,"rate":0,"minutesrunning":20},"iob_data":[{"iob":0.115,"basaliob":0.115,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:42.349Z","iobWithZeroTemp":{"iob":0.115,"basaliob":0.115,"bolussnooze":0,"activity":0.0033,"lastBolusTime":0,"time":"2024-01-05T10:32:42.349Z"}},{"iob":0.1,"basaliob":0.1,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:42.349Z","iobWithZeroTemp":{"iob":0.075,"basaliob":0.075,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:42.349Z"}},{"iob":0.086,"basaliob":0.086,"bolussnooze":0,"activity":0.0026,"lastBolusTime":0,"time":"2024-01-05T10:42:42.349Z","iobWithZeroTemp":{"iob":0.031,"basaliob":0.031,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:42.349Z"}},{"iob":0.074,"basaliob":0.074,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2024-01-05T10:47:42.349Z","iobWithZeroTemp":{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:42.349Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:52:42.349Z","iobWithZeroTemp":{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:42.349Z"}},{"iob":0.053,"basaliob":0.053,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:57:42.349Z","iobWithZeroTemp":{"iob":-0.091,"basaliob":-0.091,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T10:57:42.349Z"}},{"iob":0.044,"basaliob":0.044,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T11:02:42.349Z","iobWithZeroTemp":{"iob":-0.128,"basaliob":-0.128,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:42.349Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:07:42.349Z","iobWithZeroTemp":{"iob":-0.162,"basaliob":-0.162,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:42.349Z"}},{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:12:42.349Z","iobWithZeroTemp":{"iob":-0.196,"basaliob":-0.196,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:42.349Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:17:42.349Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:42.349Z"}},{"iob":0.019,"basaliob":0.019,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:22:42.349Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:42.349Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:42.349Z","iobWithZeroTemp":{"iob":-0.283,"basaliob":-0.283,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:42.349Z"}},{"iob":0.011,"basaliob":0.011,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:42.349Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2024-01-05T11:32:42.349Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:37:42.349Z","iobWithZeroTemp":{"iob":-0.334,"basaliob":-0.334,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:42.349Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:42.349Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:42.349Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:42.349Z","iobWithZeroTemp":{"iob":-0.377,"basaliob":-0.377,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:42.349Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:42.349Z","iobWithZeroTemp":{"iob":-0.397,"basaliob":-0.397,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:42.349Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:42.349Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:42.349Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:42.349Z","iobWithZeroTemp":{"iob":-0.434,"basaliob":-0.434,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:42.349Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:42.349Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:42.349Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:42.349Z","iobWithZeroTemp":{"iob":-0.464,"basaliob":-0.464,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:42.349Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:42.349Z","iobWithZeroTemp":{"iob":-0.478,"basaliob":-0.478,"bolussnooze":0,"activity":-0.0034,"lastBolusTime":0,"time":"2024-01-05T12:17:42.349Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:42.349Z","iobWithZeroTemp":{"iob":-0.491,"basaliob":-0.491,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:42.349Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:42.349Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:37:42.349Z","iobWithZeroTemp":{"iob":-0.525,"basaliob":-0.525,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:37:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:42:42.349Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:42:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:47:42.349Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:52:42.349Z","iobWithZeroTemp":{"iob":-0.55,"basaliob":-0.55,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:57:42.349Z","iobWithZeroTemp":{"iob":-0.558,"basaliob":-0.558,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:02:42.349Z","iobWithZeroTemp":{"iob":-0.565,"basaliob":-0.565,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T13:02:42.349Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:07:42.349Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:07:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:12:42.349Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:12:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T13:17:42.349Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:17:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:42.349Z","iobWithZeroTemp":{"iob":-0.587,"basaliob":-0.587,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:22:42.349Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:42.349Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:27:42.349Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:42.349Z","iobWithZeroTemp":{"iob":-0.594,"basaliob":-0.594,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:32:42.349Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:42.349Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:42.349Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:42.349Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:42.349Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:42.349Z","iobWithZeroTemp":{"iob":-0.604,"basaliob":-0.604,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:42.349Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:42.349Z","iobWithZeroTemp":{"iob":-0.607,"basaliob":-0.607,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:52:42.349Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:42.349Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:42.349Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:42.349Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:02:42.349Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:42.349Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:42.349Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:12:42.349Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:12:42.349Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:17:42.349Z","iobWithZeroTemp":{"iob":-0.617,"basaliob":-0.617,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:17:42.349Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:22:42.349Z","iobWithZeroTemp":{"iob":-0.619,"basaliob":-0.619,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:22:42.349Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:27:42.349Z","iobWithZeroTemp":{"iob":-0.62,"basaliob":-0.62,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T14:27:42.349Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-0.6932727272727274,"slopeFromMinDeviation":3.0729999999999995,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704450765503,"flatBGsDetected":false},"output":{"temp":"absolute","bg":82,"tick":"+0","eventualBG":78,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:32:45.503Z","sensitivityRatio":1,"variable_sens":172.1,"predBGs":{"IOB":[82,82,81,81,81,80,80,80,80,79,79,78,77,77,76,76,75,75,75,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,75],"ZT":[82,79,77,75,73,71,70,69,69,68,68,69,70,71,72,74,75,77,79,82,85,87,90],"UAM":[82,81,79,77,75,73,71,70,69,68,67,66,65,64,64,63,63,63,62,62,62,62,62,62,61,61,61,61,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,62,63]},"COB":0,"IOB":0.115,"reason":"COB: 0, Dev: 16, BGI: -3, ISF: 172, CR: 17.3, Target: 91, minPredBG 69, minGuardBG 61, IOBpredBG 75, UAMpredBG 63; minGuardBG 61<66 100m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:32:45.533Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_113747.json b/app/src/androidTest/assets/results/2024-01-05_113747.json new file mode 100644 index 00000000000..d5add0ed739 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_113747.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":71,"noise":0,"delta":-6.5,"short_avgdelta":-6.5,"long_avgdelta":-6.48,"date":1704450900000,"dura_ISF_minutes":0,"dura_ISF_average":71,"parabola_fit_correlation":0.9771,"parabola_fit_minutes":45,"parabola_fit_last_delta":-0.8242424242422124,"parabola_fit_next_delta":1.1909090909092959,"parabola_fit_a0":75.1,"parabola_fit_a1":0.18,"parabola_fit_a2":1.01,"bg_acceleration":2.0151515151515085},"currenttemp":{"temp":"absolute","duration":95,"rate":0,"minutesrunning":25},"iob_data":[{"iob":0.069,"basaliob":0.069,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:44.287Z","iobWithZeroTemp":{"iob":0.069,"basaliob":0.069,"bolussnooze":0,"activity":0.0029,"lastBolusTime":0,"time":"2024-01-05T10:37:44.287Z"}},{"iob":0.055,"basaliob":0.055,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:44.287Z","iobWithZeroTemp":{"iob":0.03,"basaliob":0.03,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:44.287Z"}},{"iob":0.043,"basaliob":0.043,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-05T10:47:44.287Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:44.287Z"}},{"iob":0.033,"basaliob":0.033,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2024-01-05T10:52:44.287Z","iobWithZeroTemp":{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:44.287Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:57:44.287Z","iobWithZeroTemp":{"iob":-0.091,"basaliob":-0.091,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:44.287Z"}},{"iob":0.016,"basaliob":0.016,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T11:02:44.287Z","iobWithZeroTemp":{"iob":-0.128,"basaliob":-0.128,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:02:44.287Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:07:44.287Z","iobWithZeroTemp":{"iob":-0.162,"basaliob":-0.162,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.287Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:12:44.287Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.287Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.287Z","iobWithZeroTemp":{"iob":-0.227,"basaliob":-0.227,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.287Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.287Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.287Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.287Z","iobWithZeroTemp":{"iob":-0.283,"basaliob":-0.283,"bolussnooze":0,"activity":-9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.287Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:44.287Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2024-01-05T11:32:44.287Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:37:44.287Z","iobWithZeroTemp":{"iob":-0.333,"basaliob":-0.333,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:44.287Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:44.287Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:44.287Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:44.287Z","iobWithZeroTemp":{"iob":-0.378,"basaliob":-0.378,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-05T11:47:44.287Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:44.287Z","iobWithZeroTemp":{"iob":-0.397,"basaliob":-0.397,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:44.287Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:44.287Z","iobWithZeroTemp":{"iob":-0.433,"basaliob":-0.433,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:07:44.287Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:07:44.287Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:12:44.287Z","iobWithZeroTemp":{"iob":-0.464,"basaliob":-0.464,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:44.287Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:17:44.287Z","iobWithZeroTemp":{"iob":-0.478,"basaliob":-0.478,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:22:44.287Z","iobWithZeroTemp":{"iob":-0.49,"basaliob":-0.49,"bolussnooze":0,"activity":-0.0036,"lastBolusTime":0,"time":"2024-01-05T12:22:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:44.287Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:44.287Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:44.287Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.0041,"lastBolusTime":0,"time":"2024-01-05T12:32:44.287Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:44.287Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:44.287Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:44.287Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:42:44.287Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:44.287Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:44.287Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:44.287Z","iobWithZeroTemp":{"iob":-0.55,"basaliob":-0.55,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:44.287Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:44.287Z","iobWithZeroTemp":{"iob":-0.557,"basaliob":-0.557,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:44.287Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:44.287Z","iobWithZeroTemp":{"iob":-0.564,"basaliob":-0.564,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T13:02:44.287Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:44.287Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:07:44.287Z"}},{"iob":-0.014,"basaliob":-0.014,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:44.287Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:12:44.287Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:44.287Z","iobWithZeroTemp":{"iob":-0.581,"basaliob":-0.581,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:17:44.287Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:44.287Z","iobWithZeroTemp":{"iob":-0.587,"basaliob":-0.587,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:22:44.287Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:44.287Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:44.287Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:44.287Z","iobWithZeroTemp":{"iob":-0.594,"basaliob":-0.594,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:44.287Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:44.287Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:44.287Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:44.287Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:42:44.287Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:44.287Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:44.287Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:44.287Z","iobWithZeroTemp":{"iob":-0.607,"basaliob":-0.607,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:52:44.287Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:44.287Z","iobWithZeroTemp":{"iob":-0.609,"basaliob":-0.609,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:44.287Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:44.287Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T14:02:44.287Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:44.287Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:44.287Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:12:44.287Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:12:44.287Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:17:44.287Z","iobWithZeroTemp":{"iob":-0.617,"basaliob":-0.617,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:17:44.287Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:22:44.287Z","iobWithZeroTemp":{"iob":-0.619,"basaliob":-0.619,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:22:44.287Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:27:44.287Z","iobWithZeroTemp":{"iob":-0.62,"basaliob":-0.62,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:27:44.287Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:32:44.287Z","iobWithZeroTemp":{"iob":-0.621,"basaliob":-0.621,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T14:32:44.287Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":-0.35645454545454547,"slopeFromMinDeviation":1.9446000000000003,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704451067399,"flatBGsDetected":false},"output":{"temp":"absolute","bg":71,"tick":-6,"eventualBG":37,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:37:47.399Z","sensitivityRatio":1,"variable_sens":265,"predBGs":{"IOB":[71,65,59,54,50,46,43,40,39,39,39,39,39],"ZT":[71,67,64,61,59,57,56,55,55,55,56,57,58,60,63,65,68,72,76,80,84,89]},"COB":0,"IOB":0.069,"reason":"COB: 0, Dev: -16, BGI: -4, ISF: 265, CR: 17.3, Target: 91, minPredBG 47, minGuardBG 31, IOBpredBG 39; minGuardBG 31<66 95m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:37:47.430Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_114246.json b/app/src/androidTest/assets/results/2024-01-05_114246.json new file mode 100644 index 00000000000..84a249efc47 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_114246.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":71,"noise":0,"delta":-2.61,"short_avgdelta":-2.61,"long_avgdelta":-4.73,"date":1704451200000,"dura_ISF_minutes":5,"dura_ISF_average":71,"parabola_fit_correlation":0.9685,"parabola_fit_minutes":45,"parabola_fit_last_delta":0.7575757575757711,"parabola_fit_next_delta":2.7878787878788014,"parabola_fit_a0":73.9,"parabola_fit_a1":1.77,"parabola_fit_a2":1.02,"bg_acceleration":2.0303030303030303},"currenttemp":{"temp":"absolute","duration":90,"rate":0,"minutesrunning":30},"iob_data":[{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:42.766Z","iobWithZeroTemp":{"iob":0.025,"basaliob":0.025,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-05T10:42:42.766Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:42.766Z","iobWithZeroTemp":{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:42.766Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-05T10:52:42.766Z","iobWithZeroTemp":{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:42.766Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-05T10:57:42.766Z","iobWithZeroTemp":{"iob":-0.09,"basaliob":-0.09,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T10:57:42.766Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:02:42.766Z","iobWithZeroTemp":{"iob":-0.127,"basaliob":-0.127,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:02:42.766Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:07:42.766Z","iobWithZeroTemp":{"iob":-0.162,"basaliob":-0.162,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:42.766Z"}},{"iob":-0.023,"basaliob":-0.023,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:42.766Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:42.766Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:42.766Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:42.766Z"}},{"iob":-0.03,"basaliob":-0.03,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:42.766Z","iobWithZeroTemp":{"iob":-0.256,"basaliob":-0.256,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:42.766Z"}},{"iob":-0.032,"basaliob":-0.032,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:42.766Z","iobWithZeroTemp":{"iob":-0.283,"basaliob":-0.283,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:42.766Z"}},{"iob":-0.034,"basaliob":-0.034,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:42.766Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2024-01-05T11:32:42.766Z"}},{"iob":-0.035,"basaliob":-0.035,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:37:42.766Z","iobWithZeroTemp":{"iob":-0.333,"basaliob":-0.333,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:42.766Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:42.766Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:42.766Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:47:42.766Z","iobWithZeroTemp":{"iob":-0.377,"basaliob":-0.377,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2024-01-05T11:47:42.766Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:52:42.766Z","iobWithZeroTemp":{"iob":-0.397,"basaliob":-0.397,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:42.766Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:42.766Z","iobWithZeroTemp":{"iob":-0.415,"basaliob":-0.415,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:42.766Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:42.766Z","iobWithZeroTemp":{"iob":-0.433,"basaliob":-0.433,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:42.766Z"}},{"iob":-0.035,"basaliob":-0.035,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:42.766Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.003,"lastBolusTime":0,"time":"2024-01-05T12:07:42.766Z"}},{"iob":-0.034,"basaliob":-0.034,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:42.766Z","iobWithZeroTemp":{"iob":-0.464,"basaliob":-0.464,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:42.766Z"}},{"iob":-0.033,"basaliob":-0.033,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:42.766Z","iobWithZeroTemp":{"iob":-0.477,"basaliob":-0.477,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:42.766Z"}},{"iob":-0.032,"basaliob":-0.032,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:42.766Z","iobWithZeroTemp":{"iob":-0.49,"basaliob":-0.49,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:42.766Z"}},{"iob":-0.031,"basaliob":-0.031,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:42.766Z","iobWithZeroTemp":{"iob":-0.502,"basaliob":-0.502,"bolussnooze":0,"activity":-0.0038,"lastBolusTime":0,"time":"2024-01-05T12:27:42.766Z"}},{"iob":-0.03,"basaliob":-0.03,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:42.766Z","iobWithZeroTemp":{"iob":-0.514,"basaliob":-0.514,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:42.766Z"}},{"iob":-0.029,"basaliob":-0.029,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:42.766Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:42.766Z"}},{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:42.766Z","iobWithZeroTemp":{"iob":-0.534,"basaliob":-0.534,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-05T12:42:42.766Z"}},{"iob":-0.026,"basaliob":-0.026,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:42.766Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:42.766Z"}},{"iob":-0.025,"basaliob":-0.025,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:42.766Z","iobWithZeroTemp":{"iob":-0.55,"basaliob":-0.55,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:52:42.766Z"}},{"iob":-0.024,"basaliob":-0.024,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:42.766Z","iobWithZeroTemp":{"iob":-0.557,"basaliob":-0.557,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:57:42.766Z"}},{"iob":-0.023,"basaliob":-0.023,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:42.766Z","iobWithZeroTemp":{"iob":-0.564,"basaliob":-0.564,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T13:02:42.766Z"}},{"iob":-0.022,"basaliob":-0.022,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:42.766Z","iobWithZeroTemp":{"iob":-0.571,"basaliob":-0.571,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:07:42.766Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:42.766Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:12:42.766Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:42.766Z","iobWithZeroTemp":{"iob":-0.581,"basaliob":-0.581,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:17:42.766Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:42.766Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:22:42.766Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:42.766Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:42.766Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:42.766Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:42.766Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:42.766Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:42.766Z"}},{"iob":-0.014,"basaliob":-0.014,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:42.766Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:42.766Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:42.766Z","iobWithZeroTemp":{"iob":-0.604,"basaliob":-0.604,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:42.766Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:42.766Z","iobWithZeroTemp":{"iob":-0.607,"basaliob":-0.607,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:52:42.766Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:42.766Z","iobWithZeroTemp":{"iob":-0.609,"basaliob":-0.609,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:42.766Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:42.766Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:02:42.766Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:42.766Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:42.766Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:12:42.766Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:12:42.766Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:17:42.766Z","iobWithZeroTemp":{"iob":-0.617,"basaliob":-0.617,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:17:42.766Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:22:42.766Z","iobWithZeroTemp":{"iob":-0.619,"basaliob":-0.619,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:22:42.766Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:27:42.766Z","iobWithZeroTemp":{"iob":-0.62,"basaliob":-0.62,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:27:42.766Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:32:42.766Z","iobWithZeroTemp":{"iob":-0.622,"basaliob":-0.622,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:32:42.766Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:37:42.766Z","iobWithZeroTemp":{"iob":-0.622,"basaliob":-0.622,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T14:37:42.766Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":2.025666666666667,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704451365932,"flatBGsDetected":false},"output":{"temp":"absolute","bg":71,"tick":-3,"eventualBG":68,"targetBG":91,"insulinReq":0,"deliverAt":"2024-01-05T10:42:45.932Z","sensitivityRatio":1,"variable_sens":268.1,"predBGs":{"IOB":[71,68,66,64,63,61,60,59,59,58,58,57,57,57,57,57,57,57,57,58,58,58,58,59,59,59,59,60,60,60,61,61,61,61,62,62,62,62,63,63,63,63,64],"ZT":[71,68,65,63,61,59,59,58,58,59,60,62,64,66,69,72,76,79,83,88],"UAM":[71,68,65,62,60,59,57,56,55,54,54,53,53,53,53,53,53,53,53,54,54,54,55,55,55,55,56,56,56,56,57,57,57,58,58,58,58,59,59,59,59,60,60,60,60,60,60,61]},"COB":0,"IOB":0.025,"reason":"COB: 0, Dev: 4, BGI: -3, ISF: 268, CR: 17.3, Target: 91, minPredBG 57, minGuardBG 53, IOBpredBG 64, UAMpredBG 61; minGuardBG 53<66 90m left and 0 ~ req 0U\/hr: no temp required","timestamp":"2024-01-05T10:42:45.963Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_114747.json b/app/src/androidTest/assets/results/2024-01-05_114747.json new file mode 100644 index 00000000000..497917553f9 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_114747.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":77,"noise":0,"delta":2.44,"short_avgdelta":2.44,"long_avgdelta":-2.06,"date":1704451500000,"dura_ISF_minutes":0,"dura_ISF_average":77,"parabola_fit_correlation":0.9853,"parabola_fit_minutes":15,"parabola_fit_last_delta":6.999999999999691,"parabola_fit_next_delta":15.499999999999725,"parabola_fit_a0":77.3,"parabola_fit_a1":11.25,"parabola_fit_a2":4.25,"bg_acceleration":8.500000000000032},"currenttemp":{"temp":"absolute","duration":85,"rate":0,"minutesrunning":35},"iob_data":[{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:44.032Z","iobWithZeroTemp":{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-05T10:47:44.032Z"}},{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:44.032Z","iobWithZeroTemp":{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-05T10:52:44.032Z"}},{"iob":-0.035,"basaliob":-0.035,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:44.032Z","iobWithZeroTemp":{"iob":-0.09,"basaliob":-0.09,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T10:57:44.032Z"}},{"iob":-0.042,"basaliob":-0.042,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-05T11:02:44.032Z","iobWithZeroTemp":{"iob":-0.127,"basaliob":-0.127,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:02:44.032Z"}},{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.032Z","iobWithZeroTemp":{"iob":-0.162,"basaliob":-0.162,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:44.032Z"}},{"iob":-0.051,"basaliob":-0.051,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.032Z","iobWithZeroTemp":{"iob":-0.195,"basaliob":-0.195,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:44.032Z"}},{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.032Z","iobWithZeroTemp":{"iob":-0.226,"basaliob":-0.226,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:44.032Z"}},{"iob":-0.056,"basaliob":-0.056,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.032Z","iobWithZeroTemp":{"iob":-0.255,"basaliob":-0.255,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:44.032Z"}},{"iob":-0.057,"basaliob":-0.057,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.032Z","iobWithZeroTemp":{"iob":-0.283,"basaliob":-0.283,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:44.032Z"}},{"iob":-0.058,"basaliob":-0.058,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:44.032Z","iobWithZeroTemp":{"iob":-0.309,"basaliob":-0.309,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:32:44.032Z"}},{"iob":-0.058,"basaliob":-0.058,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:37:44.032Z","iobWithZeroTemp":{"iob":-0.333,"basaliob":-0.333,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:37:44.032Z"}},{"iob":-0.058,"basaliob":-0.058,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:44.032Z","iobWithZeroTemp":{"iob":-0.356,"basaliob":-0.356,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:42:44.032Z"}},{"iob":-0.057,"basaliob":-0.057,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:44.032Z","iobWithZeroTemp":{"iob":-0.377,"basaliob":-0.377,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2024-01-05T11:47:44.032Z"}},{"iob":-0.056,"basaliob":-0.056,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:44.032Z","iobWithZeroTemp":{"iob":-0.397,"basaliob":-0.397,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:52:44.032Z"}},{"iob":-0.055,"basaliob":-0.055,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:57:44.032Z","iobWithZeroTemp":{"iob":-0.416,"basaliob":-0.416,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-05T11:57:44.032Z"}},{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:02:44.032Z","iobWithZeroTemp":{"iob":-0.432,"basaliob":-0.432,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:02:44.032Z"}},{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:44.032Z","iobWithZeroTemp":{"iob":-0.449,"basaliob":-0.449,"bolussnooze":0,"activity":-0.003,"lastBolusTime":0,"time":"2024-01-05T12:07:44.032Z"}},{"iob":-0.05,"basaliob":-0.05,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:44.032Z","iobWithZeroTemp":{"iob":-0.464,"basaliob":-0.464,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:12:44.032Z"}},{"iob":-0.048,"basaliob":-0.048,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:44.032Z","iobWithZeroTemp":{"iob":-0.478,"basaliob":-0.478,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-05T12:17:44.032Z"}},{"iob":-0.046,"basaliob":-0.046,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:44.032Z","iobWithZeroTemp":{"iob":-0.49,"basaliob":-0.49,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-05T12:22:44.032Z"}},{"iob":-0.044,"basaliob":-0.044,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:44.032Z","iobWithZeroTemp":{"iob":-0.502,"basaliob":-0.502,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:44.032Z"}},{"iob":-0.042,"basaliob":-0.042,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:44.032Z","iobWithZeroTemp":{"iob":-0.513,"basaliob":-0.513,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-05T12:32:44.032Z"}},{"iob":-0.04,"basaliob":-0.04,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:44.032Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:37:44.032Z"}},{"iob":-0.038,"basaliob":-0.038,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:44.032Z","iobWithZeroTemp":{"iob":-0.533,"basaliob":-0.533,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:42:44.032Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:44.032Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-05T12:47:44.032Z"}},{"iob":-0.034,"basaliob":-0.034,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:44.032Z","iobWithZeroTemp":{"iob":-0.55,"basaliob":-0.55,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-05T12:52:44.032Z"}},{"iob":-0.032,"basaliob":-0.032,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:44.032Z","iobWithZeroTemp":{"iob":-0.557,"basaliob":-0.557,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T12:57:44.032Z"}},{"iob":-0.031,"basaliob":-0.031,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:44.032Z","iobWithZeroTemp":{"iob":-0.564,"basaliob":-0.564,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:02:44.032Z"}},{"iob":-0.029,"basaliob":-0.029,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:44.032Z","iobWithZeroTemp":{"iob":-0.57,"basaliob":-0.57,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-05T13:07:44.032Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:44.032Z","iobWithZeroTemp":{"iob":-0.576,"basaliob":-0.576,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T13:12:44.032Z"}},{"iob":-0.026,"basaliob":-0.026,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:44.032Z","iobWithZeroTemp":{"iob":-0.582,"basaliob":-0.582,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T13:17:44.032Z"}},{"iob":-0.024,"basaliob":-0.024,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:44.032Z","iobWithZeroTemp":{"iob":-0.586,"basaliob":-0.586,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T13:22:44.032Z"}},{"iob":-0.022,"basaliob":-0.022,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:44.032Z","iobWithZeroTemp":{"iob":-0.59,"basaliob":-0.59,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:27:44.032Z"}},{"iob":-0.021,"basaliob":-0.021,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:44.032Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:32:44.032Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:44.032Z","iobWithZeroTemp":{"iob":-0.599,"basaliob":-0.599,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:37:44.032Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:44.032Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:42:44.032Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:44.032Z","iobWithZeroTemp":{"iob":-0.604,"basaliob":-0.604,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:47:44.032Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:44.032Z","iobWithZeroTemp":{"iob":-0.607,"basaliob":-0.607,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:52:44.032Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:44.032Z","iobWithZeroTemp":{"iob":-0.61,"basaliob":-0.61,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:57:44.032Z"}},{"iob":-0.014,"basaliob":-0.014,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:44.032Z","iobWithZeroTemp":{"iob":-0.612,"basaliob":-0.612,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T14:02:44.032Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:44.032Z","iobWithZeroTemp":{"iob":-0.614,"basaliob":-0.614,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:07:44.032Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:12:44.032Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T14:12:44.032Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:17:44.032Z","iobWithZeroTemp":{"iob":-0.618,"basaliob":-0.618,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:17:44.032Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:22:44.032Z","iobWithZeroTemp":{"iob":-0.619,"basaliob":-0.619,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:22:44.032Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:27:44.032Z","iobWithZeroTemp":{"iob":-0.62,"basaliob":-0.62,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T14:27:44.032Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:32:44.032Z","iobWithZeroTemp":{"iob":-0.621,"basaliob":-0.621,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:32:44.032Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:37:44.032Z","iobWithZeroTemp":{"iob":-0.623,"basaliob":-0.623,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T14:37:44.032Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:42:44.032Z","iobWithZeroTemp":{"iob":-0.623,"basaliob":-0.623,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T14:42:44.032Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":17.3,"sens":118,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":60,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":1.7977142857142856,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704451667183,"flatBGsDetected":false},"output":{"temp":"absolute","bg":77,"tick":"+2","eventualBG":103,"targetBG":91,"insulinReq":0.02,"deliverAt":"2024-01-05T10:47:47.183Z","sensitivityRatio":1,"variable_sens":153.5,"predBGs":{"IOB":[77,79,81,83,85,87,88,90,91,92,92,93,93,93,93,93,94,94,94,94,95,95,95,96,96,96,97,97,97,97,98,98,98,98,99,99,99,99,99,99,100],"ZT":[77,75,74,73,72,72,72,72,72,73,74,75,76,78,80,82,84,86,89,91],"UAM":[77,79,80,82,83,83,83,83,82,82,82,82,82,82,82,83,83,83,83,84,84,84,85,85,85,86,86,86,87,87,87,87,88,88,88,88,88,89,89,89,89,89,89,89,90]},"COB":0,"IOB":-0.018,"reason":"COB: 0, Dev: 24, BGI: -2, ISF: 154, CR: 17.3, Target: 91, minPredBG 94, minGuardBG 79, IOBpredBG 100, UAMpredBG 90; Eventual BG 103 >= 91, temp 0.00 < 0.41U\/hr. ","duration":30,"rate":0.41,"timestamp":"2024-01-05T10:47:47.218Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_115511.json b/app/src/androidTest/assets/results/2024-01-05_115511.json new file mode 100644 index 00000000000..dfe333af972 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_115511.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":93,"noise":0,"delta":7.67,"short_avgdelta":7.67,"long_avgdelta":2.32,"date":1704452100000,"dura_ISF_minutes":0,"dura_ISF_average":93,"parabola_fit_correlation":0,"parabola_fit_minutes":0,"parabola_fit_last_delta":0,"parabola_fit_next_delta":0,"parabola_fit_a0":0,"parabola_fit_a1":0,"parabola_fit_a2":0,"bg_acceleration":0},"currenttemp":{"temp":"absolute","duration":23,"rate":0.48840000000000006,"minutesrunning":7},"iob_data":[{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T10:55:09.381Z","iobWithZeroTemp":{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-05T10:55:09.381Z"}},{"iob":-0.034,"basaliob":-0.034,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:00:09.381Z","iobWithZeroTemp":{"iob":-0.064,"basaliob":-0.064,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-05T11:00:09.381Z"}},{"iob":-0.04,"basaliob":-0.04,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:05:09.381Z","iobWithZeroTemp":{"iob":-0.106,"basaliob":-0.106,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:05:09.381Z"}},{"iob":-0.045,"basaliob":-0.045,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:10:09.381Z","iobWithZeroTemp":{"iob":-0.148,"basaliob":-0.148,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:10:09.381Z"}},{"iob":-0.048,"basaliob":-0.048,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:15:09.381Z","iobWithZeroTemp":{"iob":-0.186,"basaliob":-0.186,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:15:09.381Z"}},{"iob":-0.051,"basaliob":-0.051,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:20:09.381Z","iobWithZeroTemp":{"iob":-0.224,"basaliob":-0.224,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:20:09.381Z"}},{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:25:09.381Z","iobWithZeroTemp":{"iob":-0.26,"basaliob":-0.26,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:25:09.381Z"}},{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:30:09.381Z","iobWithZeroTemp":{"iob":-0.293,"basaliob":-0.293,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:30:09.381Z"}},{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:35:09.381Z","iobWithZeroTemp":{"iob":-0.325,"basaliob":-0.325,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-05T11:35:09.381Z"}},{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:40:09.381Z","iobWithZeroTemp":{"iob":-0.355,"basaliob":-0.355,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-05T11:40:09.381Z"}},{"iob":-0.054,"basaliob":-0.054,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:45:09.381Z","iobWithZeroTemp":{"iob":-0.384,"basaliob":-0.384,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-05T11:45:09.381Z"}},{"iob":-0.053,"basaliob":-0.053,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:50:09.381Z","iobWithZeroTemp":{"iob":-0.411,"basaliob":-0.411,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2024-01-05T11:50:09.381Z"}},{"iob":-0.052,"basaliob":-0.052,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:55:09.381Z","iobWithZeroTemp":{"iob":-0.436,"basaliob":-0.436,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2024-01-05T11:55:09.381Z"}},{"iob":-0.051,"basaliob":-0.051,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:00:09.381Z","iobWithZeroTemp":{"iob":-0.46,"basaliob":-0.46,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-05T12:00:09.381Z"}},{"iob":-0.05,"basaliob":-0.05,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:05:09.381Z","iobWithZeroTemp":{"iob":-0.483,"basaliob":-0.483,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:05:09.381Z"}},{"iob":-0.048,"basaliob":-0.048,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:10:09.381Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0033,"lastBolusTime":0,"time":"2024-01-05T12:10:09.381Z"}},{"iob":-0.047,"basaliob":-0.047,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:15:09.381Z","iobWithZeroTemp":{"iob":-0.524,"basaliob":-0.524,"bolussnooze":0,"activity":-0.0036,"lastBolusTime":0,"time":"2024-01-05T12:15:09.381Z"}},{"iob":-0.045,"basaliob":-0.045,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:20:09.381Z","iobWithZeroTemp":{"iob":-0.542,"basaliob":-0.542,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:20:09.381Z"}},{"iob":-0.043,"basaliob":-0.043,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:25:09.381Z","iobWithZeroTemp":{"iob":-0.559,"basaliob":-0.559,"bolussnooze":0,"activity":-0.0041,"lastBolusTime":0,"time":"2024-01-05T12:25:09.381Z"}},{"iob":-0.041,"basaliob":-0.041,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:30:09.381Z","iobWithZeroTemp":{"iob":-0.574,"basaliob":-0.574,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:30:09.381Z"}},{"iob":-0.039,"basaliob":-0.039,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:35:09.381Z","iobWithZeroTemp":{"iob":-0.589,"basaliob":-0.589,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:35:09.381Z"}},{"iob":-0.038,"basaliob":-0.038,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:40:09.381Z","iobWithZeroTemp":{"iob":-0.604,"basaliob":-0.604,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T12:40:09.381Z"}},{"iob":-0.036,"basaliob":-0.036,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:45:09.381Z","iobWithZeroTemp":{"iob":-0.616,"basaliob":-0.616,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T12:45:09.381Z"}},{"iob":-0.034,"basaliob":-0.034,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:50:09.381Z","iobWithZeroTemp":{"iob":-0.628,"basaliob":-0.628,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-05T12:50:09.381Z"}},{"iob":-0.032,"basaliob":-0.032,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:55:09.381Z","iobWithZeroTemp":{"iob":-0.639,"basaliob":-0.639,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T12:55:09.381Z"}},{"iob":-0.03,"basaliob":-0.03,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:00:09.381Z","iobWithZeroTemp":{"iob":-0.649,"basaliob":-0.649,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-05T13:00:09.381Z"}},{"iob":-0.029,"basaliob":-0.029,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:05:09.381Z","iobWithZeroTemp":{"iob":-0.659,"basaliob":-0.659,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:05:09.381Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:10:09.381Z","iobWithZeroTemp":{"iob":-0.667,"basaliob":-0.667,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-05T13:10:09.381Z"}},{"iob":-0.025,"basaliob":-0.025,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:15:09.381Z","iobWithZeroTemp":{"iob":-0.675,"basaliob":-0.675,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T13:15:09.381Z"}},{"iob":-0.024,"basaliob":-0.024,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:20:09.381Z","iobWithZeroTemp":{"iob":-0.683,"basaliob":-0.683,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T13:20:09.381Z"}},{"iob":-0.022,"basaliob":-0.022,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:25:09.381Z","iobWithZeroTemp":{"iob":-0.689,"basaliob":-0.689,"bolussnooze":0,"activity":-0.0061,"lastBolusTime":0,"time":"2024-01-05T13:25:09.381Z"}},{"iob":-0.021,"basaliob":-0.021,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:30:09.381Z","iobWithZeroTemp":{"iob":-0.696,"basaliob":-0.696,"bolussnooze":0,"activity":-0.0062,"lastBolusTime":0,"time":"2024-01-05T13:30:09.381Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:35:09.381Z","iobWithZeroTemp":{"iob":-0.702,"basaliob":-0.702,"bolussnooze":0,"activity":-0.0063,"lastBolusTime":0,"time":"2024-01-05T13:35:09.381Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-3.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:40:09.381Z","iobWithZeroTemp":{"iob":-0.706,"basaliob":-0.706,"bolussnooze":0,"activity":-0.0064,"lastBolusTime":0,"time":"2024-01-05T13:40:09.381Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:45:09.381Z","iobWithZeroTemp":{"iob":-0.711,"basaliob":-0.711,"bolussnooze":0,"activity":-0.0064,"lastBolusTime":0,"time":"2024-01-05T13:45:09.381Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:50:09.381Z","iobWithZeroTemp":{"iob":-0.716,"basaliob":-0.716,"bolussnooze":0,"activity":-0.0065,"lastBolusTime":0,"time":"2024-01-05T13:50:09.381Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:55:09.381Z","iobWithZeroTemp":{"iob":-0.72,"basaliob":-0.72,"bolussnooze":0,"activity":-0.0066,"lastBolusTime":0,"time":"2024-01-05T13:55:09.381Z"}},{"iob":-0.014,"basaliob":-0.014,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:00:09.381Z","iobWithZeroTemp":{"iob":-0.724,"basaliob":-0.724,"bolussnooze":0,"activity":-0.0067,"lastBolusTime":0,"time":"2024-01-05T14:00:09.381Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:05:09.381Z","iobWithZeroTemp":{"iob":-0.727,"basaliob":-0.727,"bolussnooze":0,"activity":-0.0068,"lastBolusTime":0,"time":"2024-01-05T14:05:09.381Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:10:09.381Z","iobWithZeroTemp":{"iob":-0.73,"basaliob":-0.73,"bolussnooze":0,"activity":-0.0068,"lastBolusTime":0,"time":"2024-01-05T14:10:09.381Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:15:09.381Z","iobWithZeroTemp":{"iob":-0.732,"basaliob":-0.732,"bolussnooze":0,"activity":-0.0069,"lastBolusTime":0,"time":"2024-01-05T14:15:09.381Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:20:09.381Z","iobWithZeroTemp":{"iob":-0.735,"basaliob":-0.735,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:20:09.381Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:25:09.381Z","iobWithZeroTemp":{"iob":-0.737,"basaliob":-0.737,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:25:09.381Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:30:09.381Z","iobWithZeroTemp":{"iob":-0.739,"basaliob":-0.739,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:30:09.381Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:35:09.381Z","iobWithZeroTemp":{"iob":-0.741,"basaliob":-0.741,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:35:09.381Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:40:09.381Z","iobWithZeroTemp":{"iob":-0.742,"basaliob":-0.742,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:40:09.381Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:45:09.381Z","iobWithZeroTemp":{"iob":-0.743,"basaliob":-0.743,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:45:09.381Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:50:09.381Z","iobWithZeroTemp":{"iob":-0.745,"basaliob":-0.745,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:50:09.381Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.54,"max_basal":3.55,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":14.416666666666668,"sens":98.33333333333334,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.444,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":50,"profile_percentage":120},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":2.334888888888889,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704452110363,"flatBGsDetected":false},"output":{"temp":"absolute","bg":93,"tick":"+8","eventualBG":148,"targetBG":91,"insulinReq":0.36,"deliverAt":"2024-01-05T10:55:10.363Z","sensitivityRatio":1,"variable_sens":129.7,"predBGs":{"IOB":[93,100,106,112,117,122,126,130,132,135,136,137,137,137,137,137,138,138,138,138,139,139,139,139,140,140,140,140,140,141,141,141,141,141,142,142,142,142,142,142,142,143],"ZT":[93,92,91,91,90,90,90,90,91],"UAM":[93,100,106,112,117,121,125,128,131,132,133,133,134,134,134,134,134,134,135,135,135,135,136,136,136,137,137,137,137,137,137,138,138,138,138,138,138,139,139,139,139,139,139,139,139,140]},"COB":0,"IOB":-0.027,"reason":"COB: 0, Dev: 52, BGI: -1, ISF: 130, CR: 14.42, Target: 91, minPredBG 138, minGuardBG 100, IOBpredBG 143, UAMpredBG 140; Eventual BG 148 >= 91, temp 0.49 < 1.16U\/hr. ","duration":30,"rate":1.164,"timestamp":"2024-01-05T10:55:10.371Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-05_115754.json b/app/src/androidTest/assets/results/2024-01-05_115754.json new file mode 100644 index 00000000000..1c96ed7ea72 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-05_115754.json @@ -0,0 +1,3 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":93,"noise":0,"delta":7.67,"short_avgdelta":7.67,"long_avgdelta":2.32,"date":1704452100000,"dura_ISF_minutes":0,"dura_ISF_average":93,"parabola_fit_correlation":0,"parabola_fit_minutes":0,"parabola_fit_last_delta":0,"parabola_fit_next_delta":0,"parabola_fit_a0":0,"parabola_fit_a1":0,"parabola_fit_a2":0,"bg_acceleration":0},"currenttemp":{"temp":"absolute","duration":27,"rate":1.1543999999999999,"minutesrunning":3},"iob_data":[{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:53.841Z","iobWithZeroTemp":{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-05T10:57:53.841Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:02:53.841Z","iobWithZeroTemp":{"iob":-0.032,"basaliob":-0.032,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-05T11:02:53.841Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-05T11:07:53.841Z","iobWithZeroTemp":{"iob":-0.074,"basaliob":-0.074,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:07:53.841Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:53.841Z","iobWithZeroTemp":{"iob":-0.116,"basaliob":-0.116,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:12:53.841Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:53.841Z","iobWithZeroTemp":{"iob":-0.154,"basaliob":-0.154,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:17:53.841Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:22:53.841Z","iobWithZeroTemp":{"iob":-0.193,"basaliob":-0.193,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:22:53.841Z"}},{"iob":-0.022,"basaliob":-0.022,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:53.841Z","iobWithZeroTemp":{"iob":-0.229,"basaliob":-0.229,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:27:53.841Z"}},{"iob":-0.024,"basaliob":-0.024,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:53.841Z","iobWithZeroTemp":{"iob":-0.263,"basaliob":-0.263,"bolussnooze":0,"activity":-7.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:32:53.841Z"}},{"iob":-0.025,"basaliob":-0.025,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:37:53.841Z","iobWithZeroTemp":{"iob":-0.296,"basaliob":-0.296,"bolussnooze":0,"activity":-0.001,"lastBolusTime":0,"time":"2024-01-05T11:37:53.841Z"}},{"iob":-0.026,"basaliob":-0.026,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:42:53.841Z","iobWithZeroTemp":{"iob":-0.327,"basaliob":-0.327,"bolussnooze":0,"activity":-0.0013,"lastBolusTime":0,"time":"2024-01-05T11:42:53.841Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:47:53.841Z","iobWithZeroTemp":{"iob":-0.357,"basaliob":-0.357,"bolussnooze":0,"activity":-0.0016,"lastBolusTime":0,"time":"2024-01-05T11:47:53.841Z"}},{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-05T11:52:53.841Z","iobWithZeroTemp":{"iob":-0.386,"basaliob":-0.386,"bolussnooze":0,"activity":-0.0019,"lastBolusTime":0,"time":"2024-01-05T11:52:53.841Z"}},{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T11:57:53.841Z","iobWithZeroTemp":{"iob":-0.412,"basaliob":-0.412,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-05T11:57:53.841Z"}},{"iob":-0.028,"basaliob":-0.028,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-05T12:02:53.841Z","iobWithZeroTemp":{"iob":-0.437,"basaliob":-0.437,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2024-01-05T12:02:53.841Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:07:53.841Z","iobWithZeroTemp":{"iob":-0.46,"basaliob":-0.46,"bolussnooze":0,"activity":-0.0029,"lastBolusTime":0,"time":"2024-01-05T12:07:53.841Z"}},{"iob":-0.027,"basaliob":-0.027,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:12:53.841Z","iobWithZeroTemp":{"iob":-0.482,"basaliob":-0.482,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-05T12:12:53.841Z"}},{"iob":-0.026,"basaliob":-0.026,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:17:53.841Z","iobWithZeroTemp":{"iob":-0.503,"basaliob":-0.503,"bolussnooze":0,"activity":-0.0034,"lastBolusTime":0,"time":"2024-01-05T12:17:53.841Z"}},{"iob":-0.026,"basaliob":-0.026,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:22:53.841Z","iobWithZeroTemp":{"iob":-0.523,"basaliob":-0.523,"bolussnooze":0,"activity":-0.0036,"lastBolusTime":0,"time":"2024-01-05T12:22:53.841Z"}},{"iob":-0.025,"basaliob":-0.025,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:27:53.841Z","iobWithZeroTemp":{"iob":-0.541,"basaliob":-0.541,"bolussnooze":0,"activity":-0.0039,"lastBolusTime":0,"time":"2024-01-05T12:27:53.841Z"}},{"iob":-0.024,"basaliob":-0.024,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:32:53.841Z","iobWithZeroTemp":{"iob":-0.557,"basaliob":-0.557,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-05T12:32:53.841Z"}},{"iob":-0.023,"basaliob":-0.023,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:37:53.841Z","iobWithZeroTemp":{"iob":-0.573,"basaliob":-0.573,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-05T12:37:53.841Z"}},{"iob":-0.022,"basaliob":-0.022,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:42:53.841Z","iobWithZeroTemp":{"iob":-0.588,"basaliob":-0.588,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-05T12:42:53.841Z"}},{"iob":-0.021,"basaliob":-0.021,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:47:53.841Z","iobWithZeroTemp":{"iob":-0.601,"basaliob":-0.601,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-05T12:47:53.841Z"}},{"iob":-0.021,"basaliob":-0.021,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:52:53.841Z","iobWithZeroTemp":{"iob":-0.615,"basaliob":-0.615,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-05T12:52:53.841Z"}},{"iob":-0.02,"basaliob":-0.02,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T12:57:53.841Z","iobWithZeroTemp":{"iob":-0.627,"basaliob":-0.627,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-05T12:57:53.841Z"}},{"iob":-0.019,"basaliob":-0.019,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:02:53.841Z","iobWithZeroTemp":{"iob":-0.638,"basaliob":-0.638,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-05T13:02:53.841Z"}},{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:07:53.841Z","iobWithZeroTemp":{"iob":-0.648,"basaliob":-0.648,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-05T13:07:53.841Z"}},{"iob":-0.017,"basaliob":-0.017,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:12:53.841Z","iobWithZeroTemp":{"iob":-0.657,"basaliob":-0.657,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-05T13:12:53.841Z"}},{"iob":-0.016,"basaliob":-0.016,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:17:53.841Z","iobWithZeroTemp":{"iob":-0.666,"basaliob":-0.666,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-05T13:17:53.841Z"}},{"iob":-0.015,"basaliob":-0.015,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:22:53.841Z","iobWithZeroTemp":{"iob":-0.674,"basaliob":-0.674,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-05T13:22:53.841Z"}},{"iob":-0.014,"basaliob":-0.014,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:27:53.841Z","iobWithZeroTemp":{"iob":-0.681,"basaliob":-0.681,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-05T13:27:53.841Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:32:53.841Z","iobWithZeroTemp":{"iob":-0.688,"basaliob":-0.688,"bolussnooze":0,"activity":-0.0061,"lastBolusTime":0,"time":"2024-01-05T13:32:53.841Z"}},{"iob":-0.013,"basaliob":-0.013,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:37:53.841Z","iobWithZeroTemp":{"iob":-0.695,"basaliob":-0.695,"bolussnooze":0,"activity":-0.0062,"lastBolusTime":0,"time":"2024-01-05T13:37:53.841Z"}},{"iob":-0.012,"basaliob":-0.012,"bolussnooze":0,"activity":-2.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:42:53.841Z","iobWithZeroTemp":{"iob":-0.7,"basaliob":-0.7,"bolussnooze":0,"activity":-0.0063,"lastBolusTime":0,"time":"2024-01-05T13:42:53.841Z"}},{"iob":-0.011,"basaliob":-0.011,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:47:53.841Z","iobWithZeroTemp":{"iob":-0.705,"basaliob":-0.705,"bolussnooze":0,"activity":-0.0063,"lastBolusTime":0,"time":"2024-01-05T13:47:53.841Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:52:53.841Z","iobWithZeroTemp":{"iob":-0.71,"basaliob":-0.71,"bolussnooze":0,"activity":-0.0064,"lastBolusTime":0,"time":"2024-01-05T13:52:53.841Z"}},{"iob":-0.01,"basaliob":-0.01,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T13:57:53.841Z","iobWithZeroTemp":{"iob":-0.715,"basaliob":-0.715,"bolussnooze":0,"activity":-0.0065,"lastBolusTime":0,"time":"2024-01-05T13:57:53.841Z"}},{"iob":-0.009,"basaliob":-0.009,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:02:53.841Z","iobWithZeroTemp":{"iob":-0.719,"basaliob":-0.719,"bolussnooze":0,"activity":-0.0066,"lastBolusTime":0,"time":"2024-01-05T14:02:53.841Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:07:53.841Z","iobWithZeroTemp":{"iob":-0.722,"basaliob":-0.722,"bolussnooze":0,"activity":-0.0067,"lastBolusTime":0,"time":"2024-01-05T14:07:53.841Z"}},{"iob":-0.008,"basaliob":-0.008,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:12:53.841Z","iobWithZeroTemp":{"iob":-0.726,"basaliob":-0.726,"bolussnooze":0,"activity":-0.0067,"lastBolusTime":0,"time":"2024-01-05T14:12:53.841Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:17:53.841Z","iobWithZeroTemp":{"iob":-0.728,"basaliob":-0.728,"bolussnooze":0,"activity":-0.0068,"lastBolusTime":0,"time":"2024-01-05T14:17:53.841Z"}},{"iob":-0.007,"basaliob":-0.007,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:22:53.841Z","iobWithZeroTemp":{"iob":-0.732,"basaliob":-0.732,"bolussnooze":0,"activity":-0.0069,"lastBolusTime":0,"time":"2024-01-05T14:22:53.841Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:27:53.841Z","iobWithZeroTemp":{"iob":-0.734,"basaliob":-0.734,"bolussnooze":0,"activity":-0.0069,"lastBolusTime":0,"time":"2024-01-05T14:27:53.841Z"}},{"iob":-0.006,"basaliob":-0.006,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:32:53.841Z","iobWithZeroTemp":{"iob":-0.737,"basaliob":-0.737,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:32:53.841Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:37:53.841Z","iobWithZeroTemp":{"iob":-0.738,"basaliob":-0.738,"bolussnooze":0,"activity":-0.007,"lastBolusTime":0,"time":"2024-01-05T14:37:53.841Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:42:53.841Z","iobWithZeroTemp":{"iob":-0.74,"basaliob":-0.74,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:42:53.841Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:47:53.841Z","iobWithZeroTemp":{"iob":-0.741,"basaliob":-0.741,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:47:53.841Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-05T14:52:53.841Z","iobWithZeroTemp":{"iob":-0.743,"basaliob":-0.743,"bolussnooze":0,"activity":-0.0071,"lastBolusTime":0,"time":"2024-01-05T14:52:53.841Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.54,"max_basal":3.55,"min_bg":120,"max_bg":120,"target_bg":120,"carb_ratio":14.416666666666668,"sens":98.33333333333334,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":120,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.444,"temptargetSet":true,"autosens_max":1.5,"autosens_min":0.7, + "out_units":"mg\/dL", + "autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":45,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":50,"profile_percentage":120},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":2.334888888888889,"lastBolusTime":1703861719419,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704452274573,"flatBGsDetected":false},"output":{"temp":"absolute","bg":93,"tick":"+8","eventualBG":162,"targetBG":120,"insulinReq":0.04,"deliverAt":"2024-01-05T10:57:54.573Z","sensitivityRatio":0.5,"variable_sens":491.7,"predBGs":{"IOB":[93,100,106,112,117,122,126,130,133,135,136,137,137,137,137,137,137,138,138,138,139,139,140,140,141,141,142,142,143,143,144,144,145,145,146,146,146,146,147,147,147,147,148,148,148,148,149],"ZT":[93,90,87,84,83,82,82,83,85,87,91,94,99,105,111,118,126,134,143,152,163,174,185,197,209,222,235,248,262,276,291,305,320,336,351,367,382,398,401,401,401,401,401,401,401,401,401,401],"UAM":[93,100,106,113,119,124,129,134,138,142,145,147,148,149,150,150,150,150,151,151,152,152,153,153,154,154,155,155,156,156,157,157,157,158,158,159,159,159,159,160,160,160,160,161,161,161,161,162]},"COB":0,"IOB":0.004,"reason":"COB: 0, Dev: 67, BGI: -3, ISF: 492, CR: 14.42, Target: 120, minPredBG 138, minGuardBG 100, IOBpredBG 149, UAMpredBG 162; Eventual BG 162 >= 120, insulinReq 0.04. 27m@1.15 > 2 * insulinReq. Setting temp basal of 0.3U\/hr. ","duration":30,"rate":0.302,"timestamp":"2024-01-05T10:57:54.581Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-06_174057.json b/app/src/androidTest/assets/results/2024-01-06_174057.json new file mode 100644 index 00000000000..d378cc7062c --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-06_174057.json @@ -0,0 +1 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":82,"noise":0,"delta":10.5,"short_avgdelta":10.5,"long_avgdelta":-1.49,"date":1704559200000,"dura_ISF_minutes":0,"dura_ISF_average":82,"parabola_fit_correlation":0.9867,"parabola_fit_minutes":40,"parabola_fit_last_delta":10.872727272727149,"parabola_fit_next_delta":15.903030303030183,"parabola_fit_a0":79.8,"parabola_fit_a1":13.39,"parabola_fit_a2":2.52,"bg_acceleration":5.030303030303036},"currenttemp":{"temp":"absolute","duration":0,"rate":0},"iob_data":[{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-06T16:40:48.037Z","iobWithZeroTemp":{"iob":0.121,"basaliob":0.121,"bolussnooze":0,"activity":0.003,"lastBolusTime":0,"time":"2024-01-06T16:40:48.037Z"}},{"iob":0.107,"basaliob":0.107,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-06T16:45:48.037Z","iobWithZeroTemp":{"iob":0.082,"basaliob":0.082,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-06T16:45:48.037Z"}},{"iob":0.094,"basaliob":0.094,"bolussnooze":0,"activity":0.0024,"lastBolusTime":0,"time":"2024-01-06T16:50:48.037Z","iobWithZeroTemp":{"iob":0.039,"basaliob":0.039,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2024-01-06T16:50:48.037Z"}},{"iob":0.082,"basaliob":0.082,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-06T16:55:48.037Z","iobWithZeroTemp":{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-06T16:55:48.037Z"}},{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-06T17:00:48.037Z","iobWithZeroTemp":{"iob":-0.043,"basaliob":-0.043,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-06T17:00:48.037Z"}},{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-06T17:05:48.037Z","iobWithZeroTemp":{"iob":-0.081,"basaliob":-0.081,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-06T17:05:48.037Z"}},{"iob":0.054,"basaliob":0.054,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-06T17:10:48.037Z","iobWithZeroTemp":{"iob":-0.118,"basaliob":-0.118,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-06T17:10:48.037Z"}},{"iob":0.047,"basaliob":0.047,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-06T17:15:48.037Z","iobWithZeroTemp":{"iob":-0.152,"basaliob":-0.152,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:15:48.037Z"}},{"iob":0.04,"basaliob":0.04,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-06T17:20:48.037Z","iobWithZeroTemp":{"iob":-0.186,"basaliob":-0.186,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:20:48.037Z"}},{"iob":0.034,"basaliob":0.034,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-06T17:25:48.037Z","iobWithZeroTemp":{"iob":-0.217,"basaliob":-0.217,"bolussnooze":0,"activity":-1.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:25:48.037Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-06T17:30:48.037Z","iobWithZeroTemp":{"iob":-0.246,"basaliob":-0.246,"bolussnooze":0,"activity":-5.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:30:48.037Z"}},{"iob":0.024,"basaliob":0.024,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:35:48.037Z","iobWithZeroTemp":{"iob":-0.274,"basaliob":-0.274,"bolussnooze":0,"activity":-8.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:35:48.037Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:40:48.037Z","iobWithZeroTemp":{"iob":-0.3,"basaliob":-0.3,"bolussnooze":0,"activity":-0.0011,"lastBolusTime":0,"time":"2024-01-06T17:40:48.037Z"}},{"iob":0.017,"basaliob":0.017,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:45:48.037Z","iobWithZeroTemp":{"iob":-0.324,"basaliob":-0.324,"bolussnooze":0,"activity":-0.0014,"lastBolusTime":0,"time":"2024-01-06T17:45:48.037Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:50:48.037Z","iobWithZeroTemp":{"iob":-0.348,"basaliob":-0.348,"bolussnooze":0,"activity":-0.0017,"lastBolusTime":0,"time":"2024-01-06T17:50:48.037Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:55:48.037Z","iobWithZeroTemp":{"iob":-0.369,"basaliob":-0.369,"bolussnooze":0,"activity":-0.002,"lastBolusTime":0,"time":"2024-01-06T17:55:48.037Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:00:48.037Z","iobWithZeroTemp":{"iob":-0.389,"basaliob":-0.389,"bolussnooze":0,"activity":-0.0022,"lastBolusTime":0,"time":"2024-01-06T18:00:48.037Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:05:48.037Z","iobWithZeroTemp":{"iob":-0.408,"basaliob":-0.408,"bolussnooze":0,"activity":-0.0025,"lastBolusTime":0,"time":"2024-01-06T18:05:48.037Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:10:48.037Z","iobWithZeroTemp":{"iob":-0.426,"basaliob":-0.426,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-06T18:10:48.037Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:15:48.037Z","iobWithZeroTemp":{"iob":-0.442,"basaliob":-0.442,"bolussnooze":0,"activity":-0.003,"lastBolusTime":0,"time":"2024-01-06T18:15:48.037Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:20:48.037Z","iobWithZeroTemp":{"iob":-0.457,"basaliob":-0.457,"bolussnooze":0,"activity":-0.0032,"lastBolusTime":0,"time":"2024-01-06T18:20:48.037Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:25:48.037Z","iobWithZeroTemp":{"iob":-0.471,"basaliob":-0.471,"bolussnooze":0,"activity":-0.0034,"lastBolusTime":0,"time":"2024-01-06T18:25:48.037Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:30:48.037Z","iobWithZeroTemp":{"iob":-0.485,"basaliob":-0.485,"bolussnooze":0,"activity":-0.0036,"lastBolusTime":0,"time":"2024-01-06T18:30:48.037Z"}},{"iob":-0.002,"basaliob":-0.002,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:35:48.037Z","iobWithZeroTemp":{"iob":-0.497,"basaliob":-0.497,"bolussnooze":0,"activity":-0.0038,"lastBolusTime":0,"time":"2024-01-06T18:35:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:40:48.037Z","iobWithZeroTemp":{"iob":-0.509,"basaliob":-0.509,"bolussnooze":0,"activity":-0.004,"lastBolusTime":0,"time":"2024-01-06T18:40:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:45:48.037Z","iobWithZeroTemp":{"iob":-0.519,"basaliob":-0.519,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-06T18:45:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:50:48.037Z","iobWithZeroTemp":{"iob":-0.529,"basaliob":-0.529,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-06T18:50:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:55:48.037Z","iobWithZeroTemp":{"iob":-0.537,"basaliob":-0.537,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-06T18:55:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:00:48.037Z","iobWithZeroTemp":{"iob":-0.545,"basaliob":-0.545,"bolussnooze":0,"activity":-0.0045,"lastBolusTime":0,"time":"2024-01-06T19:00:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:05:48.037Z","iobWithZeroTemp":{"iob":-0.554,"basaliob":-0.554,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-06T19:05:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:10:48.037Z","iobWithZeroTemp":{"iob":-0.561,"basaliob":-0.561,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-06T19:10:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:15:48.037Z","iobWithZeroTemp":{"iob":-0.567,"basaliob":-0.567,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-06T19:15:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:20:48.037Z","iobWithZeroTemp":{"iob":-0.573,"basaliob":-0.573,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-06T19:20:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:25:48.037Z","iobWithZeroTemp":{"iob":-0.578,"basaliob":-0.578,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-06T19:25:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:30:48.037Z","iobWithZeroTemp":{"iob":-0.583,"basaliob":-0.583,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-06T19:30:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:35:48.037Z","iobWithZeroTemp":{"iob":-0.588,"basaliob":-0.588,"bolussnooze":0,"activity":-0.0053,"lastBolusTime":0,"time":"2024-01-06T19:35:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:40:48.037Z","iobWithZeroTemp":{"iob":-0.592,"basaliob":-0.592,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-06T19:40:48.037Z"}},{"iob":-0.005,"basaliob":-0.005,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:45:48.037Z","iobWithZeroTemp":{"iob":-0.596,"basaliob":-0.596,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-06T19:45:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:50:48.037Z","iobWithZeroTemp":{"iob":-0.599,"basaliob":-0.599,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-06T19:50:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:55:48.037Z","iobWithZeroTemp":{"iob":-0.602,"basaliob":-0.602,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-06T19:55:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:00:48.037Z","iobWithZeroTemp":{"iob":-0.605,"basaliob":-0.605,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-06T20:00:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:05:48.037Z","iobWithZeroTemp":{"iob":-0.615,"basaliob":-0.615,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-06T20:05:48.037Z"}},{"iob":-0.004,"basaliob":-0.004,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:10:48.037Z","iobWithZeroTemp":{"iob":-0.624,"basaliob":-0.624,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-06T20:10:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:15:48.037Z","iobWithZeroTemp":{"iob":-0.631,"basaliob":-0.631,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-06T20:15:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:20:48.037Z","iobWithZeroTemp":{"iob":-0.64,"basaliob":-0.64,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-06T20:20:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:25:48.037Z","iobWithZeroTemp":{"iob":-0.648,"basaliob":-0.648,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-06T20:25:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:30:48.037Z","iobWithZeroTemp":{"iob":-0.656,"basaliob":-0.656,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-06T20:30:48.037Z"}},{"iob":-0.003,"basaliob":-0.003,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:35:48.037Z","iobWithZeroTemp":{"iob":-0.663,"basaliob":-0.663,"bolussnooze":0,"activity":-0.0061,"lastBolusTime":0,"time":"2024-01-06T20:35:48.037Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":11,"sens":111,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":6.666666666666664,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7,"out_units":"mmol\/L","autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.65,"smb_delivery_ratio_max":0.95,"smb_delivery_ratio_bg_range":2.5,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":50,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":3.7302857142857144,"lastBolusTime":1704452714557,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704559256665,"flatBGsDetected":false},"output":{"temp":"absolute","bg":82,"tick":"+11","eventualBG":140,"targetBG":91,"insulinReq":0.25,"deliverAt":"2024-01-06T16:40:56.665Z","sensitivityRatio":1,"variable_sens":146.4,"predBGs":{"IOB":[82,91,100,108,115,121,126,130,133,135,137,137,136,136,135,135,134,134,134,133,133,133,133,133,133,132],"ZT":[82,80,78,76,75,73,72,72,71,71,71,72,72,73,74,75,77,78,80,82,84,87,89],"UAM":[82,91,99,107,113,118,122,125,126,127,126,126,125,124,124,123,123,123,122,122,122,122,122,121]},"COB":0,"IOB":0.121,"reason":"COB: 0, Dev: 4.2, BGI: -0.1, ISF: 8.1, CR: 11, Target: 5.1, minPredBG 7.1, minGuardBG 5.1, IOBpredBG 7.3, UAMpredBG 6.7; Eventual BG 7.8 >= 5.1, no temp, setting 0.87U\/hr. ","duration":30,"rate":0.87,"timestamp":"2024-01-06T16:40:56.734Z"}} \ No newline at end of file diff --git a/app/src/androidTest/assets/results/2024-01-06_174548.json b/app/src/androidTest/assets/results/2024-01-06_174548.json new file mode 100644 index 00000000000..0c937143438 --- /dev/null +++ b/app/src/androidTest/assets/results/2024-01-06_174548.json @@ -0,0 +1 @@ +{"algorithm":"OpenAPSSMBAutoISFPlugin","input":{"glucoseStatus":{"glucose":98,"noise":0,"delta":14.56,"short_avgdelta":14.56,"long_avgdelta":3.59,"date":1704559500000,"dura_ISF_minutes":0,"dura_ISF_average":98,"parabola_fit_correlation":0.9986,"parabola_fit_minutes":15,"parabola_fit_last_delta":14.999999999999972,"parabola_fit_next_delta":16.50000000000001,"parabola_fit_a0":97.7,"parabola_fit_a1":15.75,"parabola_fit_a2":0.75,"bg_acceleration":1.500000000000039},"currenttemp":{"temp":"absolute","duration":25,"rate":0.8140000000000001,"minutesrunning":5},"iob_data":[{"iob":0.144,"basaliob":0.144,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-06T16:45:47.052Z","iobWithZeroTemp":{"iob":0.144,"basaliob":0.144,"bolussnooze":0,"activity":0.0027,"lastBolusTime":0,"time":"2024-01-06T16:45:47.052Z"}},{"iob":0.131,"basaliob":0.131,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-06T16:50:47.052Z","iobWithZeroTemp":{"iob":0.106,"basaliob":0.106,"bolussnooze":0,"activity":0.0025,"lastBolusTime":0,"time":"2024-01-06T16:50:47.052Z"}},{"iob":0.118,"basaliob":0.118,"bolussnooze":0,"activity":0.0023,"lastBolusTime":0,"time":"2024-01-06T16:55:47.052Z","iobWithZeroTemp":{"iob":0.063,"basaliob":0.063,"bolussnooze":0,"activity":0.0022,"lastBolusTime":0,"time":"2024-01-06T16:55:47.052Z"}},{"iob":0.107,"basaliob":0.107,"bolussnooze":0,"activity":0.0021,"lastBolusTime":0,"time":"2024-01-06T17:00:47.052Z","iobWithZeroTemp":{"iob":0.022,"basaliob":0.022,"bolussnooze":0,"activity":0.0019,"lastBolusTime":0,"time":"2024-01-06T17:00:47.052Z"}},{"iob":0.097,"basaliob":0.097,"bolussnooze":0,"activity":0.002,"lastBolusTime":0,"time":"2024-01-06T17:05:47.052Z","iobWithZeroTemp":{"iob":-0.018,"basaliob":-0.018,"bolussnooze":0,"activity":0.0017,"lastBolusTime":0,"time":"2024-01-06T17:05:47.052Z"}},{"iob":0.088,"basaliob":0.088,"bolussnooze":0,"activity":0.0018,"lastBolusTime":0,"time":"2024-01-06T17:10:47.052Z","iobWithZeroTemp":{"iob":-0.056,"basaliob":-0.056,"bolussnooze":0,"activity":0.0013,"lastBolusTime":0,"time":"2024-01-06T17:10:47.052Z"}},{"iob":0.079,"basaliob":0.079,"bolussnooze":0,"activity":0.0016,"lastBolusTime":0,"time":"2024-01-06T17:15:47.052Z","iobWithZeroTemp":{"iob":-0.093,"basaliob":-0.093,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-06T17:15:47.052Z"}},{"iob":0.072,"basaliob":0.072,"bolussnooze":0,"activity":0.0015,"lastBolusTime":0,"time":"2024-01-06T17:20:47.052Z","iobWithZeroTemp":{"iob":-0.127,"basaliob":-0.127,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:20:47.052Z"}},{"iob":0.064,"basaliob":0.064,"bolussnooze":0,"activity":0.0014,"lastBolusTime":0,"time":"2024-01-06T17:25:47.052Z","iobWithZeroTemp":{"iob":-0.162,"basaliob":-0.162,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:25:47.052Z"}},{"iob":0.058,"basaliob":0.058,"bolussnooze":0,"activity":0.0012,"lastBolusTime":0,"time":"2024-01-06T17:30:47.052Z","iobWithZeroTemp":{"iob":-0.193,"basaliob":-0.193,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T17:30:47.052Z"}},{"iob":0.052,"basaliob":0.052,"bolussnooze":0,"activity":0.0011,"lastBolusTime":0,"time":"2024-01-06T17:35:47.052Z","iobWithZeroTemp":{"iob":-0.223,"basaliob":-0.223,"bolussnooze":0,"activity":-4.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:35:47.052Z"}},{"iob":0.046,"basaliob":0.046,"bolussnooze":0,"activity":0.001,"lastBolusTime":0,"time":"2024-01-06T17:40:47.052Z","iobWithZeroTemp":{"iob":-0.252,"basaliob":-0.252,"bolussnooze":0,"activity":-7.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:40:47.052Z"}},{"iob":0.041,"basaliob":0.041,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:45:47.052Z","iobWithZeroTemp":{"iob":-0.279,"basaliob":-0.279,"bolussnooze":0,"activity":-0.001,"lastBolusTime":0,"time":"2024-01-06T17:45:47.052Z"}},{"iob":0.037,"basaliob":0.037,"bolussnooze":0,"activity":9.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:50:47.052Z","iobWithZeroTemp":{"iob":-0.304,"basaliob":-0.304,"bolussnooze":0,"activity":-0.0012,"lastBolusTime":0,"time":"2024-01-06T17:50:47.052Z"}},{"iob":0.033,"basaliob":0.033,"bolussnooze":0,"activity":8.0E-4,"lastBolusTime":0,"time":"2024-01-06T17:55:47.052Z","iobWithZeroTemp":{"iob":-0.328,"basaliob":-0.328,"bolussnooze":0,"activity":-0.0015,"lastBolusTime":0,"time":"2024-01-06T17:55:47.052Z"}},{"iob":0.029,"basaliob":0.029,"bolussnooze":0,"activity":7.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:00:47.052Z","iobWithZeroTemp":{"iob":-0.35,"basaliob":-0.35,"bolussnooze":0,"activity":-0.0018,"lastBolusTime":0,"time":"2024-01-06T18:00:47.052Z"}},{"iob":0.026,"basaliob":0.026,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:05:47.052Z","iobWithZeroTemp":{"iob":-0.371,"basaliob":-0.371,"bolussnooze":0,"activity":-0.0021,"lastBolusTime":0,"time":"2024-01-06T18:05:47.052Z"}},{"iob":0.023,"basaliob":0.023,"bolussnooze":0,"activity":6.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:10:47.052Z","iobWithZeroTemp":{"iob":-0.391,"basaliob":-0.391,"bolussnooze":0,"activity":-0.0023,"lastBolusTime":0,"time":"2024-01-06T18:10:47.052Z"}},{"iob":0.02,"basaliob":0.02,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:15:47.052Z","iobWithZeroTemp":{"iob":-0.41,"basaliob":-0.41,"bolussnooze":0,"activity":-0.0026,"lastBolusTime":0,"time":"2024-01-06T18:15:47.052Z"}},{"iob":0.018,"basaliob":0.018,"bolussnooze":0,"activity":5.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:20:47.052Z","iobWithZeroTemp":{"iob":-0.426,"basaliob":-0.426,"bolussnooze":0,"activity":-0.0028,"lastBolusTime":0,"time":"2024-01-06T18:20:47.052Z"}},{"iob":0.015,"basaliob":0.015,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:25:47.052Z","iobWithZeroTemp":{"iob":-0.443,"basaliob":-0.443,"bolussnooze":0,"activity":-0.0031,"lastBolusTime":0,"time":"2024-01-06T18:25:47.052Z"}},{"iob":0.013,"basaliob":0.013,"bolussnooze":0,"activity":4.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:30:47.052Z","iobWithZeroTemp":{"iob":-0.458,"basaliob":-0.458,"bolussnooze":0,"activity":-0.0032,"lastBolusTime":0,"time":"2024-01-06T18:30:47.052Z"}},{"iob":0.012,"basaliob":0.012,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:35:47.052Z","iobWithZeroTemp":{"iob":-0.472,"basaliob":-0.472,"bolussnooze":0,"activity":-0.0035,"lastBolusTime":0,"time":"2024-01-06T18:35:47.052Z"}},{"iob":0.01,"basaliob":0.01,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:40:47.052Z","iobWithZeroTemp":{"iob":-0.485,"basaliob":-0.485,"bolussnooze":0,"activity":-0.0037,"lastBolusTime":0,"time":"2024-01-06T18:40:47.052Z"}},{"iob":0.008,"basaliob":0.008,"bolussnooze":0,"activity":3.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:45:47.052Z","iobWithZeroTemp":{"iob":-0.498,"basaliob":-0.498,"bolussnooze":0,"activity":-0.0038,"lastBolusTime":0,"time":"2024-01-06T18:45:47.052Z"}},{"iob":0.007,"basaliob":0.007,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:50:47.052Z","iobWithZeroTemp":{"iob":-0.509,"basaliob":-0.509,"bolussnooze":0,"activity":-0.0041,"lastBolusTime":0,"time":"2024-01-06T18:50:47.052Z"}},{"iob":0.006,"basaliob":0.006,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T18:55:47.052Z","iobWithZeroTemp":{"iob":-0.519,"basaliob":-0.519,"bolussnooze":0,"activity":-0.0042,"lastBolusTime":0,"time":"2024-01-06T18:55:47.052Z"}},{"iob":0.005,"basaliob":0.005,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:00:47.052Z","iobWithZeroTemp":{"iob":-0.528,"basaliob":-0.528,"bolussnooze":0,"activity":-0.0043,"lastBolusTime":0,"time":"2024-01-06T19:00:47.052Z"}},{"iob":0.004,"basaliob":0.004,"bolussnooze":0,"activity":2.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:05:47.052Z","iobWithZeroTemp":{"iob":-0.537,"basaliob":-0.537,"bolussnooze":0,"activity":-0.0044,"lastBolusTime":0,"time":"2024-01-06T19:05:47.052Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:10:47.052Z","iobWithZeroTemp":{"iob":-0.546,"basaliob":-0.546,"bolussnooze":0,"activity":-0.0046,"lastBolusTime":0,"time":"2024-01-06T19:10:47.052Z"}},{"iob":0.003,"basaliob":0.003,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:15:47.052Z","iobWithZeroTemp":{"iob":-0.553,"basaliob":-0.553,"bolussnooze":0,"activity":-0.0047,"lastBolusTime":0,"time":"2024-01-06T19:15:47.052Z"}},{"iob":0.002,"basaliob":0.002,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:20:47.052Z","iobWithZeroTemp":{"iob":-0.56,"basaliob":-0.56,"bolussnooze":0,"activity":-0.0048,"lastBolusTime":0,"time":"2024-01-06T19:20:47.052Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:25:47.052Z","iobWithZeroTemp":{"iob":-0.567,"basaliob":-0.567,"bolussnooze":0,"activity":-0.0049,"lastBolusTime":0,"time":"2024-01-06T19:25:47.052Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:30:47.052Z","iobWithZeroTemp":{"iob":-0.572,"basaliob":-0.572,"bolussnooze":0,"activity":-0.005,"lastBolusTime":0,"time":"2024-01-06T19:30:47.052Z"}},{"iob":0.001,"basaliob":0.001,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:35:47.052Z","iobWithZeroTemp":{"iob":-0.577,"basaliob":-0.577,"bolussnooze":0,"activity":-0.0051,"lastBolusTime":0,"time":"2024-01-06T19:35:47.052Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":1.0E-4,"lastBolusTime":0,"time":"2024-01-06T19:40:47.052Z","iobWithZeroTemp":{"iob":-0.583,"basaliob":-0.583,"bolussnooze":0,"activity":-0.0052,"lastBolusTime":0,"time":"2024-01-06T19:40:47.052Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:45:47.052Z","iobWithZeroTemp":{"iob":-0.587,"basaliob":-0.587,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-06T19:45:47.052Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:50:47.052Z","iobWithZeroTemp":{"iob":-0.591,"basaliob":-0.591,"bolussnooze":0,"activity":-0.0054,"lastBolusTime":0,"time":"2024-01-06T19:50:47.052Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T19:55:47.052Z","iobWithZeroTemp":{"iob":-0.595,"basaliob":-0.595,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-06T19:55:47.052Z"}},{"iob":0,"basaliob":0,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:00:47.052Z","iobWithZeroTemp":{"iob":-0.598,"basaliob":-0.598,"bolussnooze":0,"activity":-0.0055,"lastBolusTime":0,"time":"2024-01-06T20:00:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:05:47.052Z","iobWithZeroTemp":{"iob":-0.609,"basaliob":-0.609,"bolussnooze":0,"activity":-0.0056,"lastBolusTime":0,"time":"2024-01-06T20:05:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:10:47.052Z","iobWithZeroTemp":{"iob":-0.618,"basaliob":-0.618,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-06T20:10:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:15:47.052Z","iobWithZeroTemp":{"iob":-0.627,"basaliob":-0.627,"bolussnooze":0,"activity":-0.0057,"lastBolusTime":0,"time":"2024-01-06T20:15:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:20:47.052Z","iobWithZeroTemp":{"iob":-0.636,"basaliob":-0.636,"bolussnooze":0,"activity":-0.0058,"lastBolusTime":0,"time":"2024-01-06T20:20:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:25:47.052Z","iobWithZeroTemp":{"iob":-0.644,"basaliob":-0.644,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-06T20:25:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:30:47.052Z","iobWithZeroTemp":{"iob":-0.652,"basaliob":-0.652,"bolussnooze":0,"activity":-0.0059,"lastBolusTime":0,"time":"2024-01-06T20:30:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:35:47.052Z","iobWithZeroTemp":{"iob":-0.66,"basaliob":-0.66,"bolussnooze":0,"activity":-0.006,"lastBolusTime":0,"time":"2024-01-06T20:35:47.052Z"}},{"iob":-0.001,"basaliob":-0.001,"bolussnooze":0,"activity":0,"lastBolusTime":0,"time":"2024-01-06T20:40:47.052Z","iobWithZeroTemp":{"iob":-0.667,"basaliob":-0.667,"bolussnooze":0,"activity":-0.0061,"lastBolusTime":0,"time":"2024-01-06T20:40:47.052Z"}}],"profile":{"max_iob":8,"type":"current","max_daily_basal":0.45,"max_basal":2.96,"min_bg":91,"max_bg":91,"target_bg":91,"carb_ratio":11,"sens":111,"max_daily_safety_multiplier":8,"current_basal_safety_multiplier":8,"high_temptarget_raises_sensitivity":true,"low_temptarget_lowers_sensitivity":false,"sensitivity_raises_target":false,"resistance_lowers_target":false,"adv_target_adjustments":false,"exercise_mode":true,"half_basal_exercise_target":6.666666666666664,"maxCOB":120,"skip_neutral_temps":false,"remainingCarbsCap":90,"enableUAM":true,"A52_risk_enable":false,"SMBInterval":1,"enableSMB_with_COB":true,"enableSMB_with_temptarget":true,"allowSMB_with_high_temptarget":false,"enableSMB_always":true,"enableSMB_after_carbs":false,"maxSMBBasalMinutes":120,"maxUAMSMBBasalMinutes":120,"bolus_increment":0.1,"carbsReqThreshold":1,"current_basal":0.37,"temptargetSet":false,"autosens_max":1.5,"autosens_min":0.7,"out_units":"mmol\/L","autoISF_version":"3.0","enable_autoISF":true,"autoISF_max":2.5,"autoISF_min":0.4,"bgAccel_ISF_weight":0.3,"bgBrake_ISF_weight":0.16,"enable_pp_ISF_always":true,"pp_ISF_hours":10,"pp_ISF_weight":0.012,"delta_ISFrange_weight":0.13,"lower_ISFrange_weight":1.51,"higher_ISFrange_weight":0.8,"enable_dura_ISF_with_COB":true,"dura_ISF_weight":1.65,"smb_delivery_ratio":0.5,"smb_delivery_ratio_min":0.5,"smb_delivery_ratio_max":1,"smb_delivery_ratio_bg_range":5,"smb_max_range_extension":4,"enableSMB_EvenOn_OddOff":true,"enableSMB_EvenOn_OddOff_always":true,"iob_threshold_percent":50,"profile_percentage":100},"autosens_data":{"ratio":1},"meal_data":{"carbs":0,"mealCOB":0,"slopeFromMaxDeviation":0,"slopeFromMinDeviation":4.076499999999999,"lastBolusTime":1704452714557,"lastCarbTime":0},"microBolusAllowed":true,"currentTime":1704559548179,"flatBGsDetected":false},"output":{"temp":"absolute","bg":98,"tick":"+15","eventualBG":180,"targetBG":91,"insulinReq":0.93,"deliverAt":"2024-01-06T16:45:48.179Z","sensitivityRatio":1,"variable_sens":84.5,"predBGs":{"IOB":[98,111,123,134,144,152,159,165,170,173,175,176,175,175,175,174,174,174,173,173,173,173,173,173,172],"ZT":[98,97,96,95,94,93,93,92,92,92,92,92,92,93,93],"UAM":[98,111,123,134,143,151,158,163,168,171,172,172,172,172,171,171,171,170,170,170,170,169,169,169,169,169,169,169,169,169,169,169,168]},"COB":0,"IOB":0.144,"reason":"COB: 0, Dev: 5.2, BGI: -0.1, ISF: 4.7, CR: 11, Target: 5.1, minPredBG 9.4, minGuardBG 6.2, IOBpredBG 9.6, UAMpredBG 9.3; Eventual BG 10.0 >= 5.1, temp 0.81 < 2.23U\/hr. ","duration":30,"rate":2.23,"timestamp":"2024-01-06T16:45:48.182Z"}} \ No newline at end of file From a93395a6b332411c306650edd90dfc813db89d7b Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Sat, 17 Feb 2024 03:17:35 +0100 Subject: [PATCH 08/38] kt verification test incl. AutoISF - unresolved inject error --- .../OpenAPSSMBAutoISF/determine-basal.js | 1552 +++++++++++++++++ .../kotlin/app/aaps/ReplayApsResultsTest.kt | 285 ++- .../DetermineBasalAdapterAutoISFJS.kt | 352 ++++ .../aps/openAPSSMB/OpenAPSSMBPlugin.kt | 2 - 4 files changed, 2109 insertions(+), 82 deletions(-) create mode 100644 app/src/androidTest/assets/OpenAPSSMBAutoISF/determine-basal.js create mode 100644 app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPSSMBAutoISF/DetermineBasalAdapterAutoISFJS.kt diff --git a/app/src/androidTest/assets/OpenAPSSMBAutoISF/determine-basal.js b/app/src/androidTest/assets/OpenAPSSMBAutoISF/determine-basal.js new file mode 100644 index 00000000000..6294baa72c2 --- /dev/null +++ b/app/src/androidTest/assets/OpenAPSSMBAutoISF/determine-basal.js @@ -0,0 +1,1552 @@ +/* + Determine Basal + + Released under MIT license. See the accompanying LICENSE.txt file for + full terms and conditions + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + + +var round_basal = require('../round-basal') + +// Rounds value to 'digits' decimal places +function round(value, digits) +{ + if (! digits) { digits = 0; } + var scale = Math.pow(10, digits); + return Math.round(value * scale) / scale; +} + +// we expect BG to rise or fall at the rate of BGI, +// adjusted by the rate at which BG would need to rise / +// fall to get eventualBG to target over 2 hours +function calculate_expected_delta(target_bg, eventual_bg, bgi) { + // (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24 + var five_min_blocks = (2 * 60) / 5; + var target_delta = target_bg - eventual_bg; + return /* expectedDelta */ round(bgi + (target_delta / five_min_blocks), 1); +} + + +function convert_bg(value, profile) +{ + if (profile.out_units === "mmol/L") + { + return round(value / 18, 1).toFixed(1); + } + else + { + return Math.round(value); + } +} + +function enable_smb( + profile, + microBolusAllowed, + meal_data, + target_bg +) { + // disable SMB when a high temptarget is set + if (! microBolusAllowed) { + console.error("SMB disabled (!microBolusAllowed)"); + return false; + } else if (! profile.allowSMB_with_high_temptarget && profile.temptargetSet && target_bg > 100) { + console.error("SMB disabled due to high temptarget of",target_bg); + return false; + } else if (meal_data.bwFound === true && profile.A52_risk_enable === false) { + console.error("SMB disabled due to Bolus Wizard activity in the last 6 hours."); + return false; + } + + // enable SMB/UAM if always-on (unless previously disabled for high temptarget) + if (profile.enableSMB_always === true) { + if (meal_data.bwFound) { + console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard"); + } else { + console.error("SMB enabled due to enableSMB_always"); + } + return true; + } + + // enable SMB/UAM (if enabled in preferences) while we have COB + if (profile.enableSMB_with_COB === true && meal_data.mealCOB) { + if (meal_data.bwCarbs) { + console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard"); + } else { + console.error("SMB enabled for COB of",meal_data.mealCOB); + } + return true; + } + + // enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry + // (6 hours is defined in carbWindow in lib/meal/total.js) + if (profile.enableSMB_after_carbs === true && meal_data.carbs ) { + if (meal_data.bwCarbs) { + console.error("Warning: SMB enabled with Bolus Wizard carbs: be sure to easy bolus 30s before using Bolus Wizard"); + } else { + console.error("SMB enabled for 6h after carb entry"); + } + return true; + } + + // enable SMB/UAM (if enabled in preferences) if a low temptarget is set + if (profile.enableSMB_with_temptarget === true && (profile.temptargetSet && target_bg < 100)) { + if (meal_data.bwFound) { + console.error("Warning: SMB enabled within 6h of using Bolus Wizard: be sure to easy bolus 30s before using Bolus Wizard"); + } else { + console.error("SMB enabled for temptarget of",convert_bg(target_bg, profile)); + } + return true; + } + + console.error("SMB disabled (no enableSMB preferences active or no condition satisfied)"); + return false; +} + +function loop_smb(microBolusAllowed, profile, iob_data, iobTH_reduction_ratio) { + if ( !microBolusAllowed ) { + return "AAPS"; // see message in enable_smb + } + if (profile.temptargetSet && profile.enableSMB_EvenOn_OddOff || profile.min_bg==profile.max_bg && profile.enableSMB_EvenOn_OddOff_always && !profile.temptargetSet) { + var target = convert_bg(profile.target_bg, profile); + if (profile['temptargetSet']) { + msgType= "TempTarget "; + } else { + msgType = "profile target "; + } + if (profile['out_units'] == "mmol/L") { + evenTarget = ( round(target*10, 0) %2 == 0 ); + msgUnits = " has "; + msgTail = " decimal"; + } else { + evenTarget = ( target %2 == 0 ); + msgUnits = " is "; + msgTail = " number"; + } + if ( evenTarget ) { + msgEven = "even"; + } else { + msgEven = "odd"; + } + var iobTHeffective = profile.iob_threshold_percent; + if ( !evenTarget ) { + console.error("SMB disabled; " +msgType +target +msgUnits +msgEven +msgTail); + console.error("Loop at minimum power"); + return "blocked"; + } else if ( profile.max_iob==0 ) { + console.error("SMB disabled because of max_iob=0") + return "blocked"; + } else if (iobTHeffective/100 < iob_data.iob/(profile.max_iob*iobTH_reduction_ratio)) { + if (iobTH_reduction_ratio != 1) { + console.error("Full Loop modified max_iob", profile.max_iob, "to effectively", round(profile.max_iob*iobTH_reduction_ratio,2), "due to profile % and/or exercise mode"); + msg = "effective maxIOB " + round(profile.max_iob*iobTH_reduction_ratio,2); + } else { + msg = "maxIOB "+ profile.max_iob; + } + console.error("SMB disabled by Full Loop logic: iob "+iob_data.iob+" is more than "+iobTHeffective+"% of "+msg); + console.error("Full Loop capped"); + return "iobTH"; + } else { + console.error("SMB enabled; " +msgType +target +msgUnits +msgEven +msgTail); + if (profile.target_bg<100) { // indirect assessment; later set it in GUI + console.error("Loop at full power"); + return "fullLoop"; // even number + } else { + console.error("Loop at medium power"); + return "enforced"; // even number + } + } + } + console.error("Full Loop disabled"); + return "AAPS"; // leave it to standard AAPS +} + +function interpolate(xdata, profile, type) +{ // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... + // ... <--------------- glucose -------------------> + var polyX_bg = [ 50, 60, 80, 90, 100, 110, 150, 180, 200]; // later, hand it over + var polyY_bg = [-0.5, -0.5, -0.3, -0.2, 0.0, 0.0, 0.5, 0.7, 0.7]; // later, hand it over + // ... <----- delta -------> + var polyX_delta = [ 2, 7, 12, 16, 20]; // later, hand it over + var polyY_delta = [0.0, 0.0, 0.4, 0.7, 0.7]; // later, hand it over + var polyX; + var polyY; + if (type == "bg") { + polyX = polyX_bg; + polyY = polyY_bg; + } else if (type =="delta") { + polyX = polyX_delta; + polyY = polyY_delta; + } + var polymax = polyX.length-1; + var step = polyX[0]; + var sVal = polyY[0]; + var stepT= polyX[polymax]; + var sValold = polyY[polymax]; + + var newVal = 1; + var lowVal = 1; + var topVal = 1; + var lowX = 1; + var topX = 1; + var myX = 1; + var lowLabl = step; + + if (step > xdata) { + // extrapolate backwards + stepT = polyX[1]; + sValold = polyY[1]; + lowVal = sVal; + topVal = sValold; + lowX = step; + topX = stepT; + myX = xdata; + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX); + } else if (stepT < xdata) { + // extrapolate forwards + step = polyX[polymax-1]; + sVal = polyY[polymax-1]; + lowVal = sVal; + topVal = sValold; + lowX = step; + topX = stepT; + myX = xdata; + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX); + } else { + // interpolate + for (var i=0; i <= polymax; i++) { + step = polyX[i]; + sVal = polyY[i]; + if (step == xdata) { + newVal = sVal; + break; + } else if (step > xdata) { + topVal = sVal; + lowX= lowLabl; + myX = xdata; + topX= step; + newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX); + break; + } + lowVal = sVal; + lowLabl= step; + } + } + if (type == "delta") {newVal = newVal * profile['delta_ISFrange_weight']} // delta range + else if ( xdata>100) {newVal = newVal * profile['higher_ISFrange_weight']} // higher BG range + else {newVal = newVal * profile['lower_ISFrange_weight']} // lower BG range + return newVal; +} + +function withinISFlimits(liftISF, minISFReduction, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget) +{ // extracted 17.Mar.2022 + if ( liftISF < minISFReduction ) { + console.error("weakest autoISF factor", round(liftISF,2), "limited by autoISF_min", minISFReduction); + liftISF = minISFReduction; + } else if ( liftISF > maxISFReduction ) { + console.error("strongest autoISF factor", round(liftISF,2), "limited by autoISF_max", maxISFReduction); + liftISF = maxISFReduction; + } + var final_ISF = 1; + if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget ) { + final_ISF = liftISF * sensitivityRatio ; //# on top of TT modification + origin_sens = "including exercise mode impact"; + } else if ( liftISF >= 1 ) { + final_ISF = Math.max(liftISF, sensitivityRatio); + if (liftISF >= sensitivityRatio) { origin_sens = "";} // autoISF dominates + } else { + final_ISF = Math.min(liftISF, sensitivityRatio); + if (liftISF <= sensitivityRatio) { origin_sens = "";} // autoISF dominates + } + console.error("final ISF factor is", round(final_ISF,2), origin_sens); + console.error("----------------------------------"); + console.error("end autoISF"); + console.error("----------------------------------"); + return final_ISF; +} + +function autoISF(sens, origin_sens, target_bg, profile, glucose_status, meal_data, currentTime, +autosens_data, sensitivityRatio, loop_wanted_smb, high_temptarget_raises_sensitivity, normalTarget) +{ if ( !profile.enable_autoISF ) { + console.error("autoISF disabled in Preferences"); + console.error("----------------------------------"); + console.error("end autoISF"); + console.error("----------------------------------"); + return sens; + } + var dura05 = glucose_status.dura_ISF_minutes; + var avg05 = glucose_status.dura_ISF_average; + // dated 06.JUN.2021 starts + var maxISFReduction = profile.autoISF_max; + var sens_modified = false; + var pp_ISF = 1; + var delta_ISF = 1; + var acce_ISF = 1; + var acce_weight = 1; + var bg_off = target_bg+10 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 + + // calculate acce_ISF from bg acceleration and adapt ISF accordingly + var fit_corr = glucose_status.parabola_fit_correlation; + var bg_acce = glucose_status.bg_acceleration; + if (glucose_status.parabola_fit_a2 !=0 && fit_corr>=0.9) { + var minmax_delta = - glucose_status.parabola_fit_a1/2/glucose_status.parabola_fit_a2 * 5; // back from 5min block to 1 min + var minmax_value = round(glucose_status.parabola_fit_a0 - minmax_delta*minmax_delta/25*glucose_status.parabola_fit_a2, 1); + minmax_delta = round(minmax_delta, 1); + if (minmax_delta>0 && bg_acce<0) { + console.error("Parabolic fit extrapolates a maximum of", convert_bg(minmax_value,profile), "in about", minmax_delta, "minutes"); + } else if (minmax_delta>0 && bg_acce>0) { + console.error("Parabolic fit extrapolates a minimum of", convert_bg(minmax_value,profile), "in about", minmax_delta, "minutes"); + if (minmax_delta<=30 && minmax_value 0 ) { + if ( bg_acce>1) { cap_weight = 0.5; } // halve the effect below target + acce_weight = profile.bgBrake_ISF_weight; + } else if ( bg_acce < 0 ) { + acce_weight = profile.bgAccel_ISF_weight; + } + } else if ( acce_weight==1) { // above target acce goes away from target + if ( bg_acce < 0 ) { + acce_weight = profile.bgBrake_ISF_weight; + } else if ( bg_acce > 0 ) { + acce_weight = profile.bgAccel_ISF_weight; + } + } + acce_ISF = 1 + bg_acce * cap_weight * acce_weight * fit_share; + console.error("acce_ISF adaptation is", round(acce_ISF,2)); + if ( acce_ISF != 1 ) { + sens_modified = true; + } + } + + var bg_ISF = 1 + interpolate(100-bg_off, profile, "bg"); + console.error("bg_ISF adaptation is", round(bg_ISF,2)); + var liftISF = 1; + var final_ISF = 1; + if (bg_ISF<1) { + liftISF = Math.min(bg_ISF, acce_ISF); + if ( acce_ISF>1 ) { + liftISF = bg_ISF * acce_ISF; // bg_ISF could become > 1 now + console.error("bg_ISF adaptation lifted to", round(liftISF,2), "as bg accelerates already"); + } + final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget); + return Math.min(720, round(profile.sens / final_ISF, 1)); // observe ISF maximum of 720(?) + } else if ( bg_ISF > 1 ) { + sens_modified = true; + } + + var bg_delta = glucose_status.delta; + if (profile.enable_pp_ISF_always || profile.pp_ISF_hours >= (currentTime - meal_data.lastCarbTime) / 1000/3600) { // corrected logic on 17.Sep.2021 + deltaType = 'pp' + } else { + deltaType = 'delta' + } + if (bg_off > 0) { + console.error(deltaType+"_ISF adaptation by-passed as average glucose < "+target_bg+"+10"); + } else if (glucose_status.short_avgdelta<0) { + console.error(deltaType+"_ISF adaptation by-passed as no rise or too short lived"); + } else if (deltaType == 'pp') { + pp_ISF = 1 + Math.max(0, bg_delta * profile.pp_ISF_weight); + console.error("pp_ISF adaptation is", round(pp_ISF,2)); + if (pp_ISF != 1) { + sens_modified = true; + } + + } else { + delta_ISF = interpolate(bg_delta, profile, "delta"); + // mod V14d: halve the effect below target_bg+30 + if ( bg_off > -20 ) { + delta_ISF = 0.5 * delta_ISF; + } + delta_ISF = 1 + delta_ISF; + console.error("delta_ISF adaptation is", round(delta_ISF,2)); + + if (delta_ISF != 1) { + sens_modified = true; + } + } + + var dura_ISF = 1 + var weightISF = profile.dura_ISF_weight; + if (meal_data.mealCOB>0 && !profile.enable_dura_ISF_with_COB) { + console.error("dura_ISF by-passed; preferences disabled mealCOB of "+round(meal_data.mealCOB,1)); // mod 7f + } else if (dura05<10) { + console.error("dura_ISF by-passed; bg is only "+dura05+"m at level "+avg05); + } else if (avg05 <= target_bg) { + console.error("dura_ISF by-passed; avg. glucose", avg05, "below target", target_bg); + } else { + // fight the resistance at high levels + var dura05_weight = dura05 / 60; + var avg05_weight = weightISF / target_bg; + dura_ISF += dura05_weight*avg05_weight*(avg05-target_bg); + sens_modified = true; + console.error("dura_ISF adaptation is", round(dura_ISF,2), "because ISF", round(sens,1), "did not do it for", round(dura05,1),"m"); + } + if ( sens_modified ) { + liftISF = Math.max(dura_ISF, bg_ISF, delta_ISF, acce_ISF, pp_ISF); + if ( acce_ISF < 1 ) { // 13.JAN.2022 brakes on for otherwise stronger or stable ISF + console.error("strongest autoISF factor", round(liftISF,2), "weakened to", round(liftISF*acce_ISF,2), "as bg decelerates already"); + liftISF = liftISF * acce_ISF; // brakes on for otherwise stronger or stable ISF + } // brakes on for otherwise stronger or stable ISF + final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget); + return round(profile.sens / final_ISF, 1); + } + console.error("----------------------------------"); + console.error("end autoISF"); + console.error("----------------------------------"); + return sens; // mod V14j: nothing changed +} + +function determine_varSMBratio(profile, bg, target_bg, loop_wanted_smb) +{ // let SMB delivery ratio increase from min to max depending on how much bg exceeds target + var smb_delivery_ratio_bg_range = profile.smb_delivery_ratio_bg_range; + if ( smb_delivery_ratio_bg_range<10 ) { smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 } // was in mmol/l + var fix_SMB = profile.smb_delivery_ratio; + var lower_SMB = Math.min(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max); + var higher_SMB = Math.max(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max); + var higher_bg = target_bg + smb_delivery_ratio_bg_range; + var new_SMB = fix_SMB; + if ( smb_delivery_ratio_bg_range > 0 ) { + new_SMB = lower_SMB + (higher_SMB-lower_SMB)*(bg-target_bg) / smb_delivery_ratio_bg_range; + new_SMB = Math.max(lower_SMB, Math.min(higher_SMB, new_SMB)); // cap if outside target_bg--higher_bg + } + if ( loop_wanted_smb=='fullLoop' ) { // go for max impact + console.error('SMB delivery ratio set to', Math.max(fix_SMB, new_SMB), 'as max of fixed and interpolated values'); + return Math.max(fix_SMB, new_SMB); + } + if ( profile.smb_delivery_ratio_bg_range==0 ) { // deactivated in SMB extended menu + console.error('SMB delivery ratio set to fixed value', fix_SMB); + return fix_SMB; + } + if (bg <= target_bg) { + console.error('SMB delivery ratio limited by minimum value', lower_SMB); + return lower_SMB; + } + if (bg >= higher_bg) { + console.error('SMB delivery ratio limited by maximum value', higher_SMB); + return higher_SMB; + } + console.error('SMB delivery ratio set to interpolated value', new_SMB); + return new_SMB; +} + +var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, flatBGsDetected) { + var rT = {}; //short for requestedTemp + + var deliverAt = new Date(); + if (currentTime) { + deliverAt = new Date(currentTime); + } + + if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { + rT.error ='Error: could not get current basal rate'; + return rT; + } + var profile_current_basal = round_basal(profile.current_basal, profile); + var basal = profile_current_basal; + + var systemTime = new Date(); + if (currentTime) { + systemTime = currentTime; + } + var bgTime = new Date(glucose_status.date); + var minAgo = round( (systemTime - bgTime) / 60 / 1000 ,1); + + var bg = glucose_status.glucose; + var noise = glucose_status.noise; + // 38 is an xDrip error state that usually indicates sensor failure + // all other BG values between 11 and 37 mg/dL reflect non-error-code BG values, so we should zero temp for those + if (bg <= 10 || bg === 38 || noise >= 3) { //Dexcom is in ??? mode or calibrating, or xDrip reports high noise + rT.reason = "CGM is calibrating, in ??? state, or noise is high"; + } + if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future + rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime; + // if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps + } else if ( bg > 60 && flatBGsDetected) { + if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) { + rT.reason = "CGM was just calibrated"; + } else { + rT.reason = "Error: CGM data is unchanged for the past ~45m"; + } + } + if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && flatBGsDetected )) { + if (currenttemp.rate > basal) { // high temp is running + rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal; + rT.deliverAt = deliverAt; + rT.temp = 'absolute'; + rT.duration = 30; + rT.rate = basal; + return rT; + //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } else if ( currenttemp.rate === 0 && currenttemp.duration > 30 ) { //shorten long zero temps to 30m + rT.reason += ". Shortening " + currenttemp.duration + "m long zero temp to 30m. "; + rT.deliverAt = deliverAt; + rT.temp = 'absolute'; + rT.duration = 30; + rT.rate = 0; + return rT; + //return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp); + } else { //do nothing. + rT.reason += ". Temp " + currenttemp.rate + " <= current basal " + round(basal, 2) + "U/hr; doing nothing. "; + return rT; + } + } + + var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver + + // if min and max are set, then set target to their average + var target_bg; + var min_bg; + var max_bg; + if (typeof profile.min_bg !== 'undefined') { + min_bg = profile.min_bg; + } + if (typeof profile.max_bg !== 'undefined') { + max_bg = profile.max_bg; + } + if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') { + target_bg = (profile.min_bg + profile.max_bg) / 2; + } else { + rT.error ='Error: could not determine target_bg. '; + return rT; + } + + var sensitivityRatio; + var origin_sens = ""; + var exercise_ratio = 1; + var high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity; + var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled target (which might change) + if ( profile.half_basal_exercise_target ) { + var halfBasalTarget = profile.half_basal_exercise_target; + } else { + halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%) + // 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) + } + if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) { + if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + var c = halfBasalTarget - normalTarget; + // getting multiplication less or equal to 0 means that we have a really low target with a really low halfBasalTarget + // with low TT and lowTTlowersSensitivity we need autosens_max as a value + // we use multiplication instead of the division to avoid "division by zero error" + if (c * (c + target_bg-normalTarget) <= 0.0) { + sensitivityRatio = profile.autosens_max; + } else { + sensitivityRatio = c/(c+target_bg-normalTarget); + } + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max); + sensitivityRatio = round(sensitivityRatio,2); + exercise_ratio = sensitivityRatio; + origin_sens = "from TT modifier"; + console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg); + } + } else if (typeof autosens_data !== 'undefined' && autosens_data) { + sensitivityRatio = autosens_data.ratio; + console.log("Autosens ratio: "+sensitivityRatio+"; "); + } + var iobTH_reduction_ratio = profile.profile_percentage / 100 * exercise_ratio ; // later: * activityRatio; + if (sensitivityRatio) { + basal = profile.current_basal * sensitivityRatio; + basal = round_basal(basal, profile); + if (basal !== profile_current_basal) { + console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; "); + } else { + console.log("Basal unchanged: "+basal+"; "); + } + } + + // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120 + if (profile.temptargetSet) { + //console.log("Temp Target set, not adjusting with autosens; "); + } else if (typeof autosens_data !== 'undefined' && autosens_data) { + if ( profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1 ) { + // with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range + min_bg = round((min_bg - 60) / autosens_data.ratio) + 60; + max_bg = round((max_bg - 60) / autosens_data.ratio) + 60; + var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60; + // don't allow target_bg below 80 + new_target_bg = Math.max(80, new_target_bg); + if (target_bg === new_target_bg) { + console.log("target_bg unchanged: "+new_target_bg+"; "); + } else { + console.log("target_bg from "+target_bg+" to "+new_target_bg+"; "); + } + target_bg = new_target_bg; + } + } + + if (typeof iob_data === 'undefined' ) { + rT.error ='Error: iob_data undefined. '; + return rT; + } + + var iobArray = iob_data; + if (typeof(iob_data.length) && iob_data.length > 1) { + iob_data = iobArray[0]; + //console.error(JSON.stringify(iob_data[0])); + } + + if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) { + rT.error ='Error: iob_data missing some property. '; + return rT; + } + + var tick; + + if (glucose_status.delta > -0.5) { + tick = "+" + round(glucose_status.delta,0); + } else { + tick = round(glucose_status.delta,0); + } + //var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta); + var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta); + var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta); + var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta); + + var profile_sens = round(profile.sens,1) + var sens = profile.sens; + if (typeof autosens_data !== 'undefined' && autosens_data) { + sens = profile.sens / sensitivityRatio; + sens = round(sens, 1); + if (sens !== profile_sens) { + console.log("ISF from "+profile_sens+" to "+sens); + } else { + console.log("ISF unchanged: "+sens); + } + //console.log(" (autosens ratio "+sensitivityRatio+")"); + } + console.error("CR:",profile.carb_ratio); + + // compare currenttemp to iob_data.lastTemp and cancel temp if they don't match + var lastTempAge; + if (typeof iob_data.lastTemp !== 'undefined' ) { + lastTempAge = round(( new Date(systemTime).getTime() - iob_data.lastTemp.date ) / 60000); // in minutes + } else { + lastTempAge = 0; + } + + console.error("----------------------------------"); + console.error("start autoISF", profile.autoISF_version); // fit onto narrow screens + console.error("----------------------------------"); + var loop_wanted_smb = loop_smb(microBolusAllowed, profile, iob_data, iobTH_reduction_ratio); + var enableSMB = false; + if (microBolusAllowed && loop_wanted_smb != "AAPS") { + if ( loop_wanted_smb=="enforced" || loop_wanted_smb=="fullLoop" ) { // otherwise FL switched SMB off + enableSMB = true; + } + } else { enableSMB = enable_smb( + profile, + microBolusAllowed, + meal_data, + target_bg + ); + } + + sens = autoISF(sens, origin_sens, target_bg, profile, glucose_status, meal_data, currentTime, autosens_data, sensitivityRatio, loop_wanted_smb, high_temptarget_raises_sensitivity, normalTarget); + //console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m"); + var tempModulus = (lastTempAge + currenttemp.duration) % 30; + console.error("currenttemp:",round(currenttemp.rate,2),"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m"); + rT.temp = 'absolute'; + rT.deliverAt = deliverAt; + if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate !== iob_data.lastTemp.rate && lastTempAge > 10 && currenttemp.duration ) { + rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; canceling temp"; + return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp); + } + if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) { + // TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left + //if ( currenttemp.duration < iob_data.lastTemp.duration - 2) { + //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" << lastTemp duration "+round(iob_data.lastTemp.duration,1)+" from pumphistory; setting neutral temp of "+basal+"."; + //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + //} + //console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1)); + var lastTempEnded = lastTempAge - iob_data.lastTemp.duration + if ( lastTempEnded > 5 && lastTempAge > 10 ) { + rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; canceling temp"; + //console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1)); + return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp); + } + // TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries + //if ( tempModulus < 25 && tempModulus > 5 ) { + //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" + lastTempAge "+lastTempAge+" isn't a multiple of 30m; setting neutral temp of "+basal+"."; + //console.error(rT.reason); + //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + //} + } + + //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone + var bgi = round(( -iob_data.activity * sens * 5 ), 2); + // project deviations for 30 minutes + var deviation = round( 30 / 5 * ( minDelta - bgi ) ); + // don't overreact to a big negative delta: use minAvgDelta if deviation is negative + if (deviation < 0) { + deviation = round( (30 / 5) * ( minAvgDelta - bgi ) ); + // and if deviation is still negative, use long_avgdelta + if (deviation < 0) { + deviation = round( (30 / 5) * ( glucose_status.long_avgdelta - bgi ) ); + } + } + + // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity + if (iob_data.iob > 0) { + var naive_eventualBG = round( bg - (iob_data.iob * sens) ); + } else { // if IOB is negative, be more conservative and use the lower of sens, profile.sens + naive_eventualBG = round( bg - (iob_data.iob * Math.min(sens, profile.sens) ) ); + } + // and adjust it for the deviation above + var eventualBG = naive_eventualBG + deviation; + + // raise target for noisy / raw CGM data + if (glucose_status.noise >= 2) { + // increase target at least 10% (default 30%) for raw / noisy data + var noisyCGMTargetMultiplier = Math.max( 1.1, profile.noisyCGMTargetMultiplier ); + // don't allow maxRaw above 250 + var maxRaw = Math.min( 250, profile.maxRaw ); + var adjustedMinBG = round(Math.min(200, min_bg * noisyCGMTargetMultiplier )); + var adjustedTargetBG = round(Math.min(200, target_bg * noisyCGMTargetMultiplier )); + var adjustedMaxBG = round(Math.min(200, max_bg * noisyCGMTargetMultiplier )); + console.log("Raising target_bg for noisy / raw CGM data, from "+target_bg+" to "+adjustedTargetBG+"; "); + min_bg = adjustedMinBG; + target_bg = adjustedTargetBG; + max_bg = adjustedMaxBG; + // adjust target BG range if configured to bring down high BG faster + } else if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) { + // with target=100, as BG rises from 100 to 160, adjustedTarget drops from 100 to 80 + adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0); + adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0); + adjustedMaxBG = round(Math.max(80, max_bg - (bg - max_bg)/3 ),0); + // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it + //console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG); + if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) { + console.log("Adjusting targets for high BG: min_bg from "+min_bg+" to "+adjustedMinBG+"; "); + min_bg = adjustedMinBG; + } else { + console.log("min_bg unchanged: "+min_bg+"; "); + } + // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it + if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) { + console.log("target_bg from "+target_bg+" to "+adjustedTargetBG+"; "); + target_bg = adjustedTargetBG; + } else { + console.log("target_bg unchanged: "+target_bg+"; "); + } + // if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it + if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) { + console.error("max_bg from "+max_bg+" to "+adjustedMaxBG); + max_bg = adjustedMaxBG; + } else { + console.error("max_bg unchanged: "+max_bg); + } + } + + var expectedDelta = calculate_expected_delta(target_bg, eventualBG, bgi); + if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) { + rT.error ='Error: could not calculate eventualBG. '; + return rT; + } + + // min_bg of 90 -> threshold of 65, 100 -> 70 110 -> 75, and 130 -> 85 + var threshold = min_bg - 0.5*(min_bg-40); + + //console.error(reservoir_data); + + rT = { + 'temp': 'absolute' + , 'bg': bg + , 'tick': tick + , 'eventualBG': eventualBG + , 'targetBG': target_bg + , 'insulinReq': 0 + , 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run) + , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered + , 'sensitivityRatio' : sensitivityRatio // autosens ratio (fraction of normal basal) + , 'variable_sens' : sens // from autoISF + }; + + // generate predicted future BGs based on IOB, COB, and current absorption rate + + var COBpredBGs = []; + var aCOBpredBGs = []; + var IOBpredBGs = []; + var UAMpredBGs = []; + var ZTpredBGs = []; + COBpredBGs.push(bg); + aCOBpredBGs.push(bg); + IOBpredBGs.push(bg); + ZTpredBGs.push(bg); + UAMpredBGs.push(bg); + + //var enableSMB = enable_smb( // see above - pulled ahead + // profile, + // microBolusAllowed, + // meal_data, + // target_bg + //); + + // enable UAM (if enabled in preferences) + var enableUAM=(profile.enableUAM); + + + //console.error(meal_data); + // carb impact and duration are 0 unless changed below + var ci = 0; + var cid = 0; + // calculate current carb absorption rate, and how long to absorb all carbs + // CI = current carb impact on BG in mg/dL/5m + ci = round((minDelta - bgi),1); + var uci = round((minDelta - bgi),1); + // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g) + + // TODO: remove commented-out code for old behavior + //if (profile.temptargetSet) { + // if temptargetSet, use unadjusted profile.sens to allow activity mode sensitivityRatio to adjust CR + //var csf = profile.sens / profile.carb_ratio; + //} else { + // otherwise, use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments + // so that autotuned CR is still in effect even when basals and ISF are being adjusted by autosens + //var csf = sens / profile.carb_ratio; + //} + // use autosens-adjusted sens to counteract autosens meal insulin dosing adjustments so that + // autotuned CR is still in effect even when basals and ISF are being adjusted by TT or autosens + // this avoids overdosing insulin for large meals when low temp targets are active + csf = sens / profile.carb_ratio; + console.error("profile.sens:",round(profile.sens,1),"sens:",round(sens,1),"CSF:",round(csf,2)); + + var maxCarbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed + // limit Carb Impact to maxCarbAbsorptionRate * csf in mg/dL per 5m + var maxCI = round(maxCarbAbsorptionRate*csf*5/60,1) + if (ci > maxCI) { + console.error("Limiting carb impact from",ci,"to",maxCI,"mg/dL/5m (",maxCarbAbsorptionRate,"g/h )"); + ci = maxCI; + } + var remainingCATimeMin = 3; // h; duration of expected not-yet-observed carb absorption + // adjust remainingCATime (instead of CR) for autosens if sensitivityRatio defined + if (sensitivityRatio) { + remainingCATimeMin = remainingCATimeMin / sensitivityRatio; + } + // 20 g/h means that anything <= 60g will get a remainingCATimeMin, 80g will get 4h, and 120g 6h + // when actual absorption ramps up it will take over from remainingCATime + var assumedCarbAbsorptionRate = 20; // g/h; maximum rate to assume carbs will absorb if no CI observed + var remainingCATime = remainingCATimeMin; + if (meal_data.carbs) { + // if carbs * assumedCarbAbsorptionRate > remainingCATimeMin, raise it + // so <= 90g is assumed to take 3h, and 120g=4h + remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.mealCOB/assumedCarbAbsorptionRate); + var lastCarbAge = round(( new Date(systemTime).getTime() - meal_data.lastCarbTime ) / 60000); + //console.error(meal_data.lastCarbTime, lastCarbAge); + + var fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs; + remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60; + remainingCATime = round(remainingCATime,1); + //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) + console.error("Last carbs",lastCarbAge,"minutes ago; remainingCATime:",remainingCATime,"hours;",round(fractionCOBAbsorbed*100)+"% carbs absorbed"); + } + + // calculate the number of carbs absorbed over remainingCATime hours at current CI + // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL) + var totalCI = Math.max(0, ci / 5 * 60 * remainingCATime / 2); + // totalCI (mg/dL) / CSF (mg/dL/g) = total carbs absorbed (g) + var totalCA = totalCI / csf; + var remainingCarbsCap = 90; // default to 90 + var remainingCarbsFraction = 1; + if (profile.remainingCarbsCap) { remainingCarbsCap = Math.min(90,profile.remainingCarbsCap); } + if (profile.remainingCarbsFraction) { remainingCarbsFraction = Math.min(1,profile.remainingCarbsFraction); } + var remainingCarbsIgnore = 1 - remainingCarbsFraction; + var remainingCarbs = Math.max(0, meal_data.mealCOB - totalCA - meal_data.carbs*remainingCarbsIgnore); + remainingCarbs = Math.min(remainingCarbsCap,remainingCarbs); + // assume remainingCarbs will absorb in a /\ shaped bilinear curve + // peaking at remainingCATime / 2 and ending at remainingCATime hours + // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to remainingCATime/2 + // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h) + var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2); + //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime); + + // calculate peak deviation in last hour, and slope from that to current deviation + var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2); + // calculate lowest deviation in last hour, and slope from that to current deviation + var slopeFromMinDeviation = round(meal_data.slopeFromMinDeviation,2); + // assume deviations will drop back down at least at 1/3 the rate they ramped up + var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3); + //console.error(slopeFromMaxDeviation); + + var aci = 10; + //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) + // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m) + // limit cid to remainingCATime hours: the reset goes to remainingCI + if (ci === 0) { + // avoid divide by zero + cid = 0; + } else { + cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); + } + var acid = Math.max(0, meal_data.mealCOB * csf / aci ); + // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) + console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); + //console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); + var minIOBPredBG = 999; + var minCOBPredBG = 999; + var minUAMPredBG = 999; + var minGuardBG = bg; + var minCOBGuardBG = 999; + var minUAMGuardBG = 999; + var minIOBGuardBG = 999; + var minZTGuardBG = 999; + var minPredBG; + var avgPredBG; + var IOBpredBG = eventualBG; + var maxIOBPredBG = bg; + var maxCOBPredBG = bg; + var maxUAMPredBG = bg; + //var maxPredBG = bg; + var eventualPredBG = bg; + var lastIOBpredBG; + var lastCOBpredBG; + var lastUAMpredBG; + var lastZTpredBG; + var UAMduration = 0; + var remainingCItotal = 0; + var remainingCIs = []; + var predCIs = []; + try { + iobArray.forEach(function(iobTick) { + //console.error(iobTick); + var predBGI = round(( -iobTick.activity * sens * 5 ), 2); + var predZTBGI = round(( -iobTick.iobWithZeroTemp.activity * sens * 5 ), 2); + // for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero + // over 60 minutes (data points every 5m) + var predDev = ci * ( 1 - Math.min(1,IOBpredBGs.length/(60/5)) ); + IOBpredBG = IOBpredBGs[IOBpredBGs.length-1] + predBGI + predDev; + // calculate predBGs with long zero temp without deviations + var ZTpredBG = ZTpredBGs[ZTpredBGs.length-1] + predZTBGI; + // for COBpredBGs, predicted carb impact drops linearly from current carb impact down to zero + // eventually accounting for all carbs (if they can be absorbed over DIA) + var predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) ); + var predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) ); + // if any carbs aren't absorbed after remainingCATime hours, assume they'll absorb in a /\ shaped + // bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m) + // and ending at remainingCATime h (remainingCATime*12 * 5m intervals) + var intervals = Math.min( COBpredBGs.length, (remainingCATime*12)-COBpredBGs.length ); + var remainingCI = Math.max(0, intervals / (remainingCATime/2*12) * remainingCIpeak ); + remainingCItotal += predCI+remainingCI; + remainingCIs.push(round(remainingCI,0)); + predCIs.push(round(predCI,0)); + //console.log(round(predCI,1)+"+"+round(remainingCI,1)+" "); + COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI; + var aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI; + // for UAMpredBGs, predicted carb impact drops at slopeFromDeviations + // calculate predicted CI from UAM based on slopeFromDeviations + var predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) ); + // if slopeFromDeviations is too flat, predicted deviation impact drops linearly from + // current deviation down to zero over 3h (data points every 5m) + var predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) ); + //console.error(predUCIslope, predUCImax); + // predicted CI from UAM is the lesser of CI based on deviationSlope or DIA + var predUCI = Math.min(predUCIslope, predUCImax); + if(predUCI>0) { + //console.error(UAMpredBGs.length,slopeFromDeviations, predUCI); + UAMduration=round((UAMpredBGs.length+1)*5/60,1); + } + UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI; + //console.error(predBGI, predCI, predUCI); + // truncate all BG predictions at 4 hours + if ( IOBpredBGs.length < 48) { IOBpredBGs.push(IOBpredBG); } + if ( COBpredBGs.length < 48) { COBpredBGs.push(COBpredBG); } + if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); } + if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); } + if ( ZTpredBGs.length < 48) { ZTpredBGs.push(ZTpredBG); } + // calculate minGuardBGs without a wait from COB, UAM, IOB predBGs + if ( COBpredBG < minCOBGuardBG ) { minCOBGuardBG = round(COBpredBG); } + if ( UAMpredBG < minUAMGuardBG ) { minUAMGuardBG = round(UAMpredBG); } + if ( IOBpredBG < minIOBGuardBG ) { minIOBGuardBG = round(IOBpredBG); } + if ( ZTpredBG < minZTGuardBG ) { minZTGuardBG = round(ZTpredBG); } + + // set minPredBGs starting when currently-dosed insulin activity will peak + // look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins + var insulinPeakTime = 60; + // add 30m to allow for insulin delivery (SMBs or temps) + insulinPeakTime = 90; + var insulinPeak5m = (insulinPeakTime/60)*12; + //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve); + + // wait 90m before setting minIOBPredBG + if ( IOBpredBGs.length > insulinPeak5m && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } + if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } + // wait 85-105m before setting COB and 60m for UAM minPredBGs + if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > insulinPeak5m && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } + if ( (cid || remainingCIpeak > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; } + if ( enableUAM && UAMpredBGs.length > 12 && (UAMpredBG < minUAMPredBG) ) { minUAMPredBG = round(UAMpredBG); } + if ( enableUAM && UAMpredBG > maxIOBPredBG ) { maxUAMPredBG = UAMpredBG; } + }); + // set eventualBG to include effect of carbs + //console.error("PredBGs:",JSON.stringify(predBGs)); + } catch (e) { + console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled"); + } + if (meal_data.mealCOB) { + console.error("predCIs (mg/dL/5m):",predCIs.join(" ")); + console.error("remainingCIs: ",remainingCIs.join(" ")); + } + rT.predBGs = {}; + IOBpredBGs.forEach(function(p, i, theArray) { + theArray[i] = round(Math.min(401,Math.max(39,p))); + }); + for (var i=IOBpredBGs.length-1; i > 12; i--) { + if (IOBpredBGs[i-1] !== IOBpredBGs[i]) { break; } + else { IOBpredBGs.pop(); } + } + rT.predBGs.IOB = IOBpredBGs; + lastIOBpredBG=round(IOBpredBGs[IOBpredBGs.length-1]); + ZTpredBGs.forEach(function(p, i, theArray) { + theArray[i] = round(Math.min(401,Math.max(39,p))); + }); + for (i=ZTpredBGs.length-1; i > 6; i--) { + // stop displaying ZTpredBGs once they're rising and above target + if (ZTpredBGs[i-1] >= ZTpredBGs[i] || ZTpredBGs[i] <= target_bg) { break; } + else { ZTpredBGs.pop(); } + } + rT.predBGs.ZT = ZTpredBGs; + lastZTpredBG=round(ZTpredBGs[ZTpredBGs.length-1]); + if (meal_data.mealCOB > 0) { + aCOBpredBGs.forEach(function(p, i, theArray) { + theArray[i] = round(Math.min(401,Math.max(39,p))); + }); + for (i=aCOBpredBGs.length-1; i > 12; i--) { + if (aCOBpredBGs[i-1] !== aCOBpredBGs[i]) { break; } + else { aCOBpredBGs.pop(); } + } + } + if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) { + COBpredBGs.forEach(function(p, i, theArray) { + theArray[i] = round(Math.min(401,Math.max(39,p))); + }); + for (i=COBpredBGs.length-1; i > 12; i--) { + if (COBpredBGs[i-1] !== COBpredBGs[i]) { break; } + else { COBpredBGs.pop(); } + } + rT.predBGs.COB = COBpredBGs; + lastCOBpredBG=round(COBpredBGs[COBpredBGs.length-1]); + eventualBG = Math.max(eventualBG, round(COBpredBGs[COBpredBGs.length-1]) ); + } + if (ci > 0 || remainingCIpeak > 0) { + if (enableUAM) { + UAMpredBGs.forEach(function(p, i, theArray) { + theArray[i] = round(Math.min(401,Math.max(39,p))); + }); + for (i=UAMpredBGs.length-1; i > 12; i--) { + if (UAMpredBGs[i-1] !== UAMpredBGs[i]) { break; } + else { UAMpredBGs.pop(); } + } + rT.predBGs.UAM = UAMpredBGs; + lastUAMpredBG=round(UAMpredBGs[UAMpredBGs.length-1]); + if (UAMpredBGs[UAMpredBGs.length-1]) { + eventualBG = Math.max(eventualBG, round(UAMpredBGs[UAMpredBGs.length-1]) ); + } + } + + // set eventualBG based on COB or UAM predBGs + rT.eventualBG = eventualBG; + } + + console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours"); + + + minIOBPredBG = Math.max(39,minIOBPredBG); + minCOBPredBG = Math.max(39,minCOBPredBG); + minUAMPredBG = Math.max(39,minUAMPredBG); + minPredBG = round(minIOBPredBG); + + var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs; + // if we have COB and UAM is enabled, average both + if ( minUAMPredBG < 999 && minCOBPredBG < 999 ) { + // weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB + avgPredBG = round( (1-fractionCarbsLeft)*UAMpredBG + fractionCarbsLeft*COBpredBG ); + // if UAM is disabled, average IOB and COB + } else if ( minCOBPredBG < 999 ) { + avgPredBG = round( (IOBpredBG + COBpredBG)/2 ); + // if we have UAM but no COB, average IOB and UAM + } else if ( minUAMPredBG < 999 ) { + avgPredBG = round( (IOBpredBG + UAMpredBG)/2 ); + } else { + avgPredBG = round( IOBpredBG ); + } + // if avgPredBG is below minZTGuardBG, bring it up to that level + if ( minZTGuardBG > avgPredBG ) { + avgPredBG = minZTGuardBG; + } + + // if we have both minCOBGuardBG and minUAMGuardBG, blend according to fractionCarbsLeft + if ( (cid || remainingCIpeak > 0) ) { + if ( enableUAM ) { + minGuardBG = fractionCarbsLeft*minCOBGuardBG + (1-fractionCarbsLeft)*minUAMGuardBG; + } else { + minGuardBG = minCOBGuardBG; + } + } else if ( enableUAM ) { + minGuardBG = minUAMGuardBG; + } else { + minGuardBG = minIOBGuardBG; + } + minGuardBG = round(minGuardBG); + //console.error(minCOBGuardBG, minUAMGuardBG, minIOBGuardBG, minGuardBG); + + var minZTUAMPredBG = minUAMPredBG; + // if minZTGuardBG is below threshold, bring down any super-high minUAMPredBG by averaging + // this helps prevent UAM from giving too much insulin in case absorption falls off suddenly + if ( minZTGuardBG < threshold ) { + minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2; + // if minZTGuardBG is between threshold and target, blend in the averaging + } else if ( minZTGuardBG < target_bg ) { + // target 100, threshold 70, minZTGuardBG 85 gives 50%: (85-70) / (100-70) + var blendPct = (minZTGuardBG-threshold) / (target_bg-threshold); + var blendedMinZTGuardBG = minUAMPredBG*blendPct + minZTGuardBG*(1-blendPct); + minZTUAMPredBG = (minUAMPredBG + blendedMinZTGuardBG) / 2; + //minZTUAMPredBG = minUAMPredBG - target_bg + minZTGuardBG; + // if minUAMPredBG is below minZTGuardBG, bring minUAMPredBG up by averaging + // this allows more insulin if lastUAMPredBG is below target, but minZTGuardBG is still high + } else if ( minZTGuardBG > minUAMPredBG ) { + minZTUAMPredBG = (minUAMPredBG + minZTGuardBG) / 2; + } + minZTUAMPredBG = round(minZTUAMPredBG); + //console.error("minUAMPredBG:",minUAMPredBG,"minZTGuardBG:",minZTGuardBG,"minZTUAMPredBG:",minZTUAMPredBG); + // if any carbs have been entered recently + if (meal_data.carbs) { + + // if UAM is disabled, use max of minIOBPredBG, minCOBPredBG + if ( ! enableUAM && minCOBPredBG < 999 ) { + minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG)); + // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher + } else if ( minCOBPredBG < 999 ) { + // calculate blendedMinPredBG based on how many carbs remain as COB + var blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minZTUAMPredBG; + // if blendedMinPredBG > minCOBPredBG, use that instead + minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG)); + // if carbs have been entered, but have expired, use minUAMPredBG + } else if ( enableUAM ) { + minPredBG = minZTUAMPredBG; + } else { + minPredBG = minGuardBG; + } + // in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG + } else if ( enableUAM ) { + minPredBG = round(Math.max(minIOBPredBG,minZTUAMPredBG)); + } + + // make sure minPredBG isn't higher than avgPredBG + minPredBG = Math.min( minPredBG, avgPredBG ); + + console.log("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG+" minZTGuardBG: "+minZTGuardBG); + if (minCOBPredBG < 999) { + console.log("minCOBPredBG: "+minCOBPredBG); + } + if (minUAMPredBG < 999) { + console.log("minUAMPredBG: "+minUAMPredBG); + } + console.error("avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs); + // But if the COB line falls off a cliff, don't trust UAM too much: + // use maxCOBPredBG if it's been set and lower than minPredBG + if ( maxCOBPredBG > bg ) { + minPredBG = Math.min(minPredBG, maxCOBPredBG); + } + + rT.COB=meal_data.mealCOB; + rT.IOB=iob_data.iob; + rT.reason="COB: " + round(meal_data.mealCOB, 1) + ", Dev: " + convert_bg(deviation, profile) + ", BGI: " + convert_bg(bgi, profile) + ", ISF: " + convert_bg(sens, profile) + ", CR: " + round(profile.carb_ratio, 2) + ", Target: " + convert_bg(target_bg, profile) + ", minPredBG " + convert_bg(minPredBG, profile) + ", minGuardBG " + convert_bg(minGuardBG, profile) + ", IOBpredBG " + convert_bg(lastIOBpredBG, profile); + if (lastCOBpredBG > 0) { + rT.reason += ", COBpredBG " + convert_bg(lastCOBpredBG, profile); + } + if (lastUAMpredBG > 0) { + rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile) + } + rT.reason += "; "; + // use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39 + var carbsReqBG = naive_eventualBG; + if ( carbsReqBG < 40 ) { + carbsReqBG = Math.min( minGuardBG, carbsReqBG ); + } + var bgUndershoot = threshold - carbsReqBG; + // calculate how long until COB (or IOB) predBGs drop below min_bg + var minutesAboveMinBG = 240; + var minutesAboveThreshold = 240; + if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) { + for (i=0; i maxDeltaPercentage * bg ) { + console.error("maxDelta",convert_bg(maxDelta, profile)+" >", maxDeltaPercentage*100+"% of BG "+convert_bg(bg, profile)+"- disabling SMB"); + rT.reason += "maxDelta "+convert_bg(maxDelta, profile)+" > "+maxDeltaPercentage*100+"% of BG "+convert_bg(bg, profile)+": SMB disabled; "; + enableSMB = false; + } + + console.error("BG projected to remain above",convert_bg(min_bg, profile),"for",minutesAboveMinBG,"minutes"); + if ( minutesAboveThreshold < 240 || minutesAboveMinBG < 60 ) { + console.error("BG projected to remain above",convert_bg(threshold,profile),"for",minutesAboveThreshold,"minutes"); + } + // include at least minutesAboveThreshold worth of zero temps in calculating carbsReq + // always include at least 30m worth of zero temp (carbs to 80, low temp up to target) + var zeroTempDuration = minutesAboveThreshold; + // BG undershoot, minus effect of zero temps until hitting min_bg, converted to grams, minus COB + var zeroTempEffect = profile.current_basal*sens*zeroTempDuration/60; + // don't count the last 25% of COB against carbsReq + var COBforCarbsReq = Math.max(0, meal_data.mealCOB - 0.25*meal_data.carbs); + var carbsReq = (bgUndershoot - zeroTempEffect) / csf - COBforCarbsReq; + zeroTempEffect = round(zeroTempEffect); + carbsReq = round(carbsReq); + console.error("naive_eventualBG:",naive_eventualBG,"bgUndershoot:",bgUndershoot,"zeroTempDuration:",zeroTempDuration,"zeroTempEffect:",zeroTempEffect,"carbsReq:",carbsReq); + if ( carbsReq >= profile.carbsReqThreshold && minutesAboveThreshold <= 45 ) { + rT.carbsReq = carbsReq; + rT.carbsReqWithin = minutesAboveThreshold; + rT.reason += carbsReq + " add'l carbs req w/in " + minutesAboveThreshold + "m; "; + } + + // don't low glucose suspend if IOB is already super negative and BG is rising faster than predicted + if (bg < threshold && iob_data.iob < -profile.current_basal*20/60 && minDelta > 0 && minDelta > expectedDelta) { + rT.reason += "IOB "+iob_data.iob+" < " + round(-profile.current_basal*20/60,2); + rT.reason += " and minDelta " + convert_bg(minDelta, profile) + " > " + "expectedDelta " + convert_bg(expectedDelta, profile) + "; "; + // predictive low glucose suspend mode: BG is / is projected to be < threshold + } else if ( bg < threshold || minGuardBG < threshold ) { + rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile); + bgUndershoot = target_bg - minGuardBG; + var worstCaseInsulinReq = bgUndershoot / sens; + var durationReq = round(60*worstCaseInsulinReq / profile.current_basal); + durationReq = round(durationReq/30)*30; + // always set a 30-120m zero temp (oref0-pump-loop will let any longer SMB zero temp run) + durationReq = Math.min(120,Math.max(30,durationReq)); + return tempBasalFunctions.setTempBasal(0, durationReq, profile, rT, currenttemp); + } + + // if not in LGS mode, cancel temps before the top of the hour to reduce beeping/vibration + // console.error(profile.skip_neutral_temps, rT.deliverAt.getMinutes()); + if ( profile.skip_neutral_temps && rT.deliverAt.getMinutes() >= 55 ) { + rT.reason += "; Canceling temp at " + rT.deliverAt.getMinutes() + "m past the hour. "; + return tempBasalFunctions.setTempBasal(0, 0, profile, rT, currenttemp); + } + + if (eventualBG < min_bg) { // if eventual BG is below target: + rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile); + // if 5m or 30m avg BG is rising faster than expected delta + if ( minDelta > expectedDelta && minDelta > 0 && !carbsReq ) { + // if naive_eventualBG < 40, set a 30m zero temp (oref0-pump-loop will let any longer SMB zero temp run) + if (naive_eventualBG < 40) { + rT.reason += ", naive_eventualBG < 40. "; + return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp); + } + if (glucose_status.delta > minDelta) { + rT.reason += ", but Delta " + convert_bg(tick, profile) + " > expectedDelta " + convert_bg(expectedDelta, profile); + } else { + rT.reason += ", but Min. Delta " + minDelta.toFixed(2) + " > Exp. Delta " + convert_bg(expectedDelta, profile); + } + if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { + rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. "; + return rT; + } else { + rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. "; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + } + + // calculate 30m low-temp required to get projected BG up to target + // multiply by 2 to low-temp faster for increased hypo safety + var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / sens); + insulinReq = round( insulinReq , 2); + // calculate naiveInsulinReq based on naive_eventualBG + var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens); + naiveInsulinReq = round( naiveInsulinReq , 2); + if (minDelta < 0 && minDelta > expectedDelta) { + // if we're barely falling, newinsulinReq should be barely negative + var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2); + //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); + insulinReq = newinsulinReq; + } + // rate required to deliver insulinReq less insulin over 30m: + var rate = basal + (2 * insulinReq); + rate = round_basal(rate, profile); + + // if required temp < existing temp basal + var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60; + // if current temp would deliver a lot (30% of basal) less than the required insulin, + // by both normal and naive calculations, then raise the rate + var minInsulinReq = Math.min(insulinReq,naiveInsulinReq); + if (insulinScheduled < minInsulinReq - basal*0.3) { + rT.reason += ", "+currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " is a lot less than needed. "; + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8)) { + rT.reason += ", temp " + currenttemp.rate + " ~< req " + round(rate, 2) + "U/hr. "; + return rT; + } else { + // calculate a long enough zero temp to eventually correct back up to target + if ( rate <=0 ) { + bgUndershoot = target_bg - naive_eventualBG; + worstCaseInsulinReq = bgUndershoot / sens; + durationReq = round(60*worstCaseInsulinReq / profile.current_basal); + if (durationReq < 0) { + durationReq = 0; + // don't set a temp longer than 120 minutes + } else { + durationReq = round(durationReq/30)*30; + durationReq = Math.min(120,Math.max(0,durationReq)); + } + //console.error(durationReq); + if (durationReq > 0) { + rT.reason += ", setting " + durationReq + "m zero temp. "; + return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp); + } + } else { + rT.reason += ", setting " + round(rate, 2) + "U/hr. "; + } + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + } + + // if eventual BG is above min but BG is falling faster than expected Delta + if (minDelta < expectedDelta) { + // if in SMB mode, don't cancel SMB zero temp + if (! (microBolusAllowed && enableSMB)) { + if (glucose_status.delta < minDelta) { + rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Delta " + convert_bg(tick, profile) + " < Exp. Delta " + convert_bg(expectedDelta, profile); + } else { + rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " > " + convert_bg(min_bg, profile) + " but Min. Delta " + minDelta.toFixed(2) + " < Exp. Delta " + convert_bg(expectedDelta, profile); + } + if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { + rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. "; + return rT; + } else { + rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. "; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + } + } + // eventualBG or minPredBG is below max_bg + if (Math.min(eventualBG,minPredBG) < max_bg) { + // if in SMB mode, don't cancel SMB zero temp + if (! (microBolusAllowed && enableSMB )) { + rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(minPredBG, profile)+" in range: no temp required"; + if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { + rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. "; + return rT; + } else { + rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. "; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + } + } + + // eventual BG is at/above target + // if iob is over max, just cancel any temps + if ( eventualBG >= max_bg ) { + rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", "; + } + if (iob_data.iob > max_iob) { + rT.reason += "IOB " + round(iob_data.iob,2) + " > max_iob " + max_iob; + if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { + rT.reason += ", temp " + currenttemp.rate + " ~ req " + round(basal, 2) + "U/hr. "; + return rT; + } else { + rT.reason += "; setting current basal of " + round(basal, 2) + " as temp. "; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + } else { // otherwise, calculate 30m high-temp required to get projected BG down to target + + // insulinReq is the additional insulin required to get minPredBG down to target_bg + //console.error(minPredBG,eventualBG); + insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / sens, 2); + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-iob_data.iob) { + rT.reason += "max_iob " + max_iob + ", "; + console.error("InsReq", round(insulinReq,2), "capped at", round(max_iob-iob_data.iob,2), "to not exceed max_iob"); + insulinReq = max_iob-iob_data.iob; + } + + // rate required to deliver insulinReq more insulin over 30m: + rate = basal + (2 * insulinReq); + rate = round_basal(rate, profile); + insulinReq = round(insulinReq,3); + rT.insulinReq = insulinReq; + //console.error(iob_data.lastBolusTime); + // minutes since last bolus + var lastBolusAge = round(( new Date(systemTime).getTime() - iob_data.lastBolusTime ) / 60000,1); + //console.error(lastBolusAge); + //console.error(profile.temptargetSet, target_bg, rT.COB); + // only allow microboluses with COB or low temp targets, or within DIA hours of a bolus + if (microBolusAllowed && enableSMB && bg > threshold) { + // never bolus more than maxSMBBasalMinutes worth of basal + var mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3); + var smb_max_range = profile.smb_max_range_extension; + if (typeof profile.maxSMBBasalMinutes === 'undefined' ) { + var maxBolus = round(smb_max_range * profile.current_basal * 30 / 60 ,1); + console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m"); + // if IOB covers more than COB, limit maxBolus to 30m of basal + } else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) { + console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq); + if (profile.maxUAMSMBBasalMinutes) { + console.error("profile.maxUAMSMBBasalMinutes:",profile.maxUAMSMBBasalMinutes,"profile.current_basal:",profile.current_basal); + maxBolus = round(smb_max_range * profile.current_basal * profile.maxUAMSMBBasalMinutes / 60 ,1); + } else { + console.error("profile.maxUAMSMBBasalMinutes undefined: defaulting to 30m"); + maxBolus = round(smb_max_range * profile.current_basal * 30 / 60 ,1); + } + } else { + console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal); + maxBolus = round(smb_max_range * profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1); + } + // bolus 1/2 the insulinReq, up to maxBolus, rounding down to nearest bolus increment + var roundSMBTo = 1 / profile.bolus_increment; + var smb_ratio = determine_varSMBratio(profile, bg, target_bg, loop_wanted_smb); + + var microBolus = Math.min(insulinReq*smb_ratio, maxBolus); + // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun + var iobTHtolerance = 130; + var iobTHvirtual = profile.iob_threshold_percent*iobTHtolerance/10000 * profile.max_iob * iobTH_reduction_ratio; + if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb=="fullLoop" || loop_wanted_smb=="enforced")) { + microBolus = iobTHvirtual - iob_data.iob; + console.error("Full loop capped SMB at", round(microBolus,2), "to not exceed", iobTHtolerance, "% of effective iobTH", round(iobTHvirtual/iobTHtolerance*100,2)+"U"); + } + microBolus = Math.floor(microBolus*roundSMBTo)/roundSMBTo; + // calculate a long enough zero temp to eventually correct back up to target + var smbTarget = target_bg; + worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens; + durationReq = round(60*worstCaseInsulinReq / profile.current_basal); + + // if insulinReq > 0 but not enough for a microBolus, don't set an SMB zero temp + if (insulinReq > 0 && microBolus < profile.bolus_increment) { + durationReq = 0; + } + + var smbLowTempReq = 0; + if (durationReq <= 0) { + durationReq = 0; + // don't set an SMB zero temp longer than 60 minutes + } else if (durationReq >= 30) { + durationReq = round(durationReq/30)*30; + durationReq = Math.min(60,Math.max(0,durationReq)); + } else { + // if SMB durationReq is less than 30m, set a nonzero low temp + smbLowTempReq = round( basal * durationReq/30 ,2); + durationReq = 30; + } + rT.reason += " insulinReq " + insulinReq; + if (microBolus >= maxBolus) { + rT.reason += "; maxBolus " + maxBolus; + } + if (durationReq > 0) { + rT.reason += "; setting " + durationReq + "m low temp of " + smbLowTempReq + "U/h"; + } + rT.reason += ". "; + + //allow SMBs every 3 minutes by default + var SMBInterval = 3; + if (profile.SMBInterval) { + // allow SMBIntervals between 1 and 10 minutes + SMBInterval = Math.min(10,Math.max(1,profile.SMBInterval)); + } + var nextBolusMins = round(SMBInterval-lastBolusAge,0); + var nextBolusSeconds = round((SMBInterval - lastBolusAge) * 60, 0) % 60; + //console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq); + console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m "+smbLowTempReq+"U/h temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus); + if (lastBolusAge > SMBInterval) { + if (microBolus > 0) { + rT.units = microBolus; + rT.reason += "Microbolusing " + microBolus + "U. "; + } + } else { + rT.reason += "Waiting " + nextBolusMins + "m " + nextBolusSeconds + "s to microbolus again. "; + } + //rT.reason += ". "; + + // if no zero temp is required, don't return yet; allow later code to set a high temp + if (durationReq > 0) { + rT.rate = smbLowTempReq; + rT.duration = durationReq; + return rT; + } + + } + + var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile); + + if (rate > maxSafeBasal) { + rT.reason += "adj. req. rate: "+round(rate, 2)+" to maxSafeBasal: "+maxSafeBasal+", "; + rate = round_basal(maxSafeBasal, profile); + } + + insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60; + if (insulinScheduled >= insulinReq * 2) { // if current temp would deliver >2x more than the required insulin, lower the rate + rT.reason += currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " > 2 * insulinReq. Setting temp basal of " + round(rate, 2) + "U/hr. "; + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + + if (typeof currenttemp.duration === 'undefined' || currenttemp.duration === 0) { // no temp is set + rT.reason += "no temp, setting " + round(rate, 2) + "U/hr. "; + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + + if (currenttemp.duration > 5 && (round_basal(rate, profile) <= round_basal(currenttemp.rate, profile))) { // if required temp <~ existing temp basal + rT.reason += "temp " + (currenttemp.rate).toFixed(2) + " >~ req " + round(rate, 2) + "U/hr. "; + return rT; + } + + // required temp > existing temp basal + rT.reason += "temp " + (currenttemp.rate).toFixed(2) + " < " + round(rate, 2) + "U/hr. "; + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + +}; + +module.exports = determine_basal; diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 48d7f0adfb7..4fb42475efa 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -10,6 +10,7 @@ import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.maintenance.FileListProvider @@ -25,6 +26,8 @@ import app.aaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import app.aaps.plugins.aps.openAPSSMB.DetermineBasalSMB import app.aaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import app.aaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS +import app.aaps.plugins.aps.openAPSAutoISF.DetermineBasalAutoISF +import app.aaps.plugins.aps.openAPSSMBAutoISF.DetermineBasalAdapterAutoISFJS import app.aaps.plugins.aps.utils.ScriptReader import com.google.common.truth.Truth.assertThat import dagger.android.HasAndroidInjector @@ -49,6 +52,7 @@ class ReplayApsResultsTest @Inject constructor() { @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var determineBasalAMA: DetermineBasalAMA @Inject lateinit var determineBasalSMBDynamicISF: DetermineBasalSMB + @Inject lateinit var determineBasalAutoISF: DetermineBasalAutoISF @Inject lateinit var sp: SP @Inject lateinit var dateUtil: DateUtil @@ -70,6 +74,7 @@ class ReplayApsResultsTest @Inject constructor() { @Suppress("SpellCheckingInspection") var amas = 0 @Suppress("SpellCheckingInspection") var smbs = 0 @Suppress("SpellCheckingInspection") var dynisfs = 0 + @Suppress("SpellCheckingInspection") var autoisfs = 0 val results = readResultFiles() assertThat(results.size).isGreaterThan(0) results.forEach { test -> @@ -82,18 +87,20 @@ class ReplayApsResultsTest @Inject constructor() { val output = JSONObject(outputString) aapsLogger.info(LTag.CORE, "***** File: $filename *****") when (algorithm) { - OpenAPSSMBPlugin::class.simpleName -> smbs++ - "OpenAPSSMBDynamicISFPlugin" -> dynisfs++ - OpenAPSAMAPlugin::class.simpleName -> amas++ + OpenAPSSMBPlugin::class.simpleName -> smbs++ + "OpenAPSSMBAutoISFPlugin" -> autoisfs++ + "OpenAPSSMBDynamicISFPlugin" -> dynisfs++ + OpenAPSAMAPlugin::class.simpleName -> amas++ } when (algorithm) { - OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) - "OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) - OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) - else -> error("Unsupported") + OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) + "OpenAPSSMBAutoISFPlugin" -> testOpenAPSSMBAutoISF(filename, input, output, injector) + "OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) + OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) + else -> error("Unsupported") } } - aapsLogger.info(LTag.CORE, "\n**********\nAMA: $amas\nSMB: $smbs\nDynISFs: $dynisfs\nJS time: $jsTime\nKT time: $ktTime\n**********") + aapsLogger.info(LTag.CORE, "\n**********\nAMA: $amas\nSMB: $smbs\nDynISFs: $dynisfs\nAutoISFs: $autoisfs\nJS time: $jsTime\nKT time: $ktTime\n**********") } private fun testOpenAPSSMB(filename: String, input: JSONObject, output: JSONObject, injector: HasAndroidInjector) { @@ -211,30 +218,7 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = 0.0, insulinDivisor = 0, - TDD = 0.0, - autoISF_version = "", - enable_autoISF = false, - autoISF_max = 1.0, - autoISF_min = 1.0, - bgAccel_ISF_weight = 0.0, - bgBrake_ISF_weight = 0.0, - enable_pp_ISF_always = false, - pp_ISF_hours = 3, - pp_ISF_weight = 0.0, - delta_ISFrange_weight = 0.0, - lower_ISFrange_weight = 0.0, - higher_ISFrange_weight = 0.0, - enable_dura_ISF_with_COB = false, - dura_ISF_weight = 0.0, - smb_delivery_ratio = 0.0, - smb_delivery_ratio_min = 0.0, - smb_delivery_ratio_max = 0.0, - smb_delivery_ratio_bg_range = 0.0, - smb_max_range_extension = 1.0, - enableSMB_EvenOn_OddOff = false, - enableSMB_EvenOn_OddOff_always = false, - iob_threshold_percent = 100, - profile_percentage = 100 + TDD = 0.0 ) val meatData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), @@ -398,30 +382,7 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = determineBasalResult.profile.getDouble("variable_sens"), insulinDivisor = determineBasalResult.profile.getInt("insulinDivisor"), - TDD = determineBasalResult.profile.getDouble("TDD"), - autoISF_version = "", - enable_autoISF = false, - autoISF_max = 1.0, - autoISF_min = 1.0, - bgAccel_ISF_weight = 0.0, - bgBrake_ISF_weight = 0.0, - enable_pp_ISF_always = false, - pp_ISF_hours = 3, - pp_ISF_weight = 0.0, - delta_ISFrange_weight = 0.0, - lower_ISFrange_weight = 0.0, - higher_ISFrange_weight = 0.0, - enable_dura_ISF_with_COB = false, - dura_ISF_weight = 0.0, - smb_delivery_ratio = 0.0, - smb_delivery_ratio_min = 0.0, - smb_delivery_ratio_max = 0.0, - smb_delivery_ratio_bg_range = 0.0, - smb_max_range_extension = 1.0, - enableSMB_EvenOn_OddOff = false, - enableSMB_EvenOn_OddOff_always = false, - iob_threshold_percent = 100, - profile_percentage = 100 + TDD = determineBasalResult.profile.getDouble("TDD") ) val meatData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), @@ -579,30 +540,7 @@ class ReplayApsResultsTest @Inject constructor() { out_units = determineBasalResult.profile.optString("out_units"), variable_sens = 0.0, insulinDivisor = 0, - TDD = 0.0, - autoISF_version = "", - enable_autoISF = false, - autoISF_max = 1.0, - autoISF_min = 1.0, - bgAccel_ISF_weight = 0.0, - bgBrake_ISF_weight = 0.0, - enable_pp_ISF_always = false, - pp_ISF_hours = 3, - pp_ISF_weight = 0.0, - delta_ISFrange_weight = 0.0, - lower_ISFrange_weight = 0.0, - higher_ISFrange_weight = 0.0, - enable_dura_ISF_with_COB = false, - dura_ISF_weight = 0.0, - smb_delivery_ratio = 0.0, - smb_delivery_ratio_min = 0.0, - smb_delivery_ratio_max = 0.0, - smb_delivery_ratio_bg_range = 0.0, - smb_max_range_extension = 1.0, - enableSMB_EvenOn_OddOff = false, - enableSMB_EvenOn_OddOff_always = false, - iob_threshold_percent = 100, - profile_percentage = 100 + TDD = 0.0 ) val mealData = MealData( carbs = determineBasalResult.mealData.getDouble("carbs"), @@ -645,6 +583,193 @@ class ReplayApsResultsTest @Inject constructor() { assertThat(resultKt.variable_sens ?: Double.NaN).isEqualTo(result?.json()?.optDouble("variable_sens")) } + private fun testOpenAPSSMBAutoISF(filename: String, input: JSONObject, output: JSONObject, injector: HasAndroidInjector) { + val startJs = System.currentTimeMillis() + val determineBasalResult = DetermineBasalAdapterAutoISFJS(ScriptReader(), injector) + determineBasalResult.profile = input.getJSONObject("profile") + determineBasalResult.glucoseStatus = input.getJSONObject("glucoseStatus") + determineBasalResult.iobData = input.getJSONArray("iob_data") + determineBasalResult.mealData = input.getJSONObject("meal_data") + determineBasalResult.currentTemp = input.getJSONObject("currenttemp") + determineBasalResult.autosensData = input.getJSONObject("autosens_data") + determineBasalResult.microBolusAllowed = input.getBoolean("microBolusAllowed") + determineBasalResult.currentTime = input.getLong("currentTime") + determineBasalResult.flatBGsDetected = input.getBoolean("flatBGsDetected") + val result = determineBasalResult.invoke() + val endJs = System.currentTimeMillis() + jsTime += (endJs - startJs) + + aapsLogger.info(LTag.APS, "Expected --> $output") + assertThat(result).isNotNull() + JSONAssert.assertEquals( + "Error in file $filename", + output.toString(), + result?.json()?.apply { + // this is added afterwards to json. Copy from original + put("timestamp", output.getString("timestamp")) + }.toString(), + CustomComparator(JSONCompareMode.LENIENT, Customization("tick") { o1: Any?, o2: Any? -> o1.toString() == o2.toString() }) + ) + + // Exclude these with whole number delta as the alg is producing different results + // on inputs like 2.0 which are evaluated as Int 2 + val delta = determineBasalResult.glucoseStatus.getDouble("delta") + if (floor(delta) == delta) return + // Pass to DetermineBasalSMB + + if (determineBasalResult.profile.optString("out_units") == "mmol/L") + sp.putString(app.aaps.core.keys.R.string.key_units, GlucoseUnit.MMOL.asText) + else + sp.putString(app.aaps.core.keys.R.string.key_units, GlucoseUnit.MGDL.asText) + + val startKt = System.currentTimeMillis() + val glucoseStatus = GlucoseStatus( + glucose = determineBasalResult.glucoseStatus.getDouble("glucose"), + noise = determineBasalResult.glucoseStatus.getDouble("noise"), + delta = determineBasalResult.glucoseStatus.getDouble("delta"), + shortAvgDelta = determineBasalResult.glucoseStatus.getDouble("short_avgdelta"), + longAvgDelta = determineBasalResult.glucoseStatus.getDouble("long_avgdelta"), + date = determineBasalResult.glucoseStatus.getLong("date"), + duraISFminutes = determineBasalResult.glucoseStatus.getDouble("dura_ISF_minutes"), + duraISFaverage = determineBasalResult.glucoseStatus.getDouble("dura_ISF_average"), + a0 = determineBasalResult.glucoseStatus.getDouble("parabola_fit_a0"), + a1 = determineBasalResult.glucoseStatus.getDouble("parabola_fit_a1"), + a2 = determineBasalResult.glucoseStatus.getDouble("parabola_fit_a2"), + bgAcceleration = determineBasalResult.glucoseStatus.getDouble("bg_acceleration"), + corrSqu = determineBasalResult.glucoseStatus.getDouble("parabola_fit_correlation") + ) + val currentTemp = CurrentTemp( + duration = determineBasalResult.currentTemp.getInt("duration"), + rate = determineBasalResult.currentTemp.getDouble("rate"), + minutesrunning = null + ) + val autosensData = AutosensResult( + ratio = determineBasalResult.autosensData.getDouble("ratio") + ) + + fun JSONObject.toIob(): IobTotal = + IobTotal( + time = dateUtil.fromISODateString(this.getString("time")), + iob = this.getDouble("iob"), + basaliob = this.getDouble("basaliob"), + bolussnooze = this.getDouble("bolussnooze"), + activity = this.getDouble("activity"), + lastBolusTime = this.getLong("lastBolusTime"), + iobWithZeroTemp = this.optJSONObject("iobWithZeroTemp")?.toIob() + ) + + val iobData = arrayListOf() + for (i in 0 until determineBasalResult.iobData!!.length()) + iobData.add(determineBasalResult.iobData!!.getJSONObject(i).toIob()) + val currentTime = determineBasalResult.currentTime + val profile = AutoISFProfile( + dia = 0.0, + min_5m_carbimpact = 0.0, + max_iob = determineBasalResult.profile.getDouble("max_iob"), + max_daily_basal = determineBasalResult.profile.getDouble("max_daily_basal"), + max_basal = determineBasalResult.profile.getDouble("max_basal"), + min_bg = determineBasalResult.profile.getDouble("min_bg"), + max_bg = determineBasalResult.profile.getDouble("max_bg"), + target_bg = determineBasalResult.profile.getDouble("target_bg"), + carb_ratio = determineBasalResult.profile.getDouble("carb_ratio"), + sens = determineBasalResult.profile.getDouble("sens"), + autosens_adjust_targets = false, + max_daily_safety_multiplier = determineBasalResult.profile.getDouble("max_daily_safety_multiplier"), + current_basal_safety_multiplier = determineBasalResult.profile.getDouble("current_basal_safety_multiplier"), + lgsThreshold = null, + high_temptarget_raises_sensitivity = determineBasalResult.profile.getBoolean("high_temptarget_raises_sensitivity"), + low_temptarget_lowers_sensitivity = determineBasalResult.profile.getBoolean("low_temptarget_lowers_sensitivity"), + sensitivity_raises_target = determineBasalResult.profile.getBoolean("sensitivity_raises_target"), + resistance_lowers_target = determineBasalResult.profile.getBoolean("resistance_lowers_target"), + adv_target_adjustments = determineBasalResult.profile.getBoolean("adv_target_adjustments"), + exercise_mode = determineBasalResult.profile.getBoolean("exercise_mode"), + half_basal_exercise_target = determineBasalResult.profile.getInt("half_basal_exercise_target"), + maxCOB = determineBasalResult.profile.getInt("maxCOB"), + skip_neutral_temps = determineBasalResult.profile.getBoolean("skip_neutral_temps"), + remainingCarbsCap = determineBasalResult.profile.getInt("remainingCarbsCap"), + enableUAM = determineBasalResult.profile.getBoolean("enableUAM"), + A52_risk_enable = determineBasalResult.profile.getBoolean("A52_risk_enable"), + SMBInterval = determineBasalResult.profile.getInt("SMBInterval"), + enableSMB_with_COB = determineBasalResult.profile.getBoolean("enableSMB_with_COB"), + enableSMB_with_temptarget = determineBasalResult.profile.getBoolean("enableSMB_with_temptarget"), + allowSMB_with_high_temptarget = determineBasalResult.profile.getBoolean("allowSMB_with_high_temptarget"), + enableSMB_always = determineBasalResult.profile.getBoolean("enableSMB_always"), + enableSMB_after_carbs = determineBasalResult.profile.getBoolean("enableSMB_after_carbs"), + maxSMBBasalMinutes = determineBasalResult.profile.getInt("maxSMBBasalMinutes"), + maxUAMSMBBasalMinutes = determineBasalResult.profile.getInt("maxUAMSMBBasalMinutes"), + bolus_increment = determineBasalResult.profile.getDouble("bolus_increment"), + carbsReqThreshold = determineBasalResult.profile.getInt("carbsReqThreshold"), + current_basal = determineBasalResult.profile.getDouble("current_basal"), + temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), + autosens_max = determineBasalResult.profile.getDouble("autosens_max"), + out_units = determineBasalResult.profile.optString("out_units"), + autoISF_version = determineBasalResult.profile.optString("autoISF_version"), + enable_autoISF = determineBasalResult.profile.getBoolean("enable_autoISF"), + autoISF_max = determineBasalResult.profile.getDouble("autoISF_max"), + autoISF_min = determineBasalResult.profile.getDouble("autoISF_min"), + bgAccel_ISF_weight = determineBasalResult.profile.getDouble("bgAccel_ISF_weight"), + bgBrake_ISF_weight = determineBasalResult.profile.getDouble("bgBrake_ISF_weight"), + enable_pp_ISF_always = determineBasalResult.profile.getBoolean("enable_pp_ISF_always"), + pp_ISF_hours = determineBasalResult.profile.getInt("pp_ISF_hours"), + pp_ISF_weight = determineBasalResult.profile.getDouble("pp_ISF_weight"), + delta_ISFrange_weight = determineBasalResult.profile.getDouble("delta_ISFrange_weight"), + lower_ISFrange_weight = determineBasalResult.profile.getDouble("lower_ISFrange_weight"), + higher_ISFrange_weight = determineBasalResult.profile.getDouble("higher_ISFrange_weight"), + enable_dura_ISF_with_COB = determineBasalResult.profile.getBoolean("enable_dura_ISF_with_COB"), + dura_ISF_weight = determineBasalResult.profile.getDouble("dura_ISF_weight"), + smb_delivery_ratio = determineBasalResult.profile.getDouble("smb_delivery_ratio"), + smb_delivery_ratio_min = determineBasalResult.profile.getDouble("smb_delivery_ratio_min"), + smb_delivery_ratio_max = determineBasalResult.profile.getDouble("smb_delivery_ratio_max"), + smb_delivery_ratio_bg_range = determineBasalResult.profile.getDouble("smb_delivery_ratio_bg_range"), + smb_max_range_extension = determineBasalResult.profile.getDouble("smb_max_range_extension"), + enableSMB_EvenOn_OddOff = determineBasalResult.profile.getBoolean("enableSMB_EvenOn_OddOff"), + enableSMB_EvenOn_OddOff_always = determineBasalResult.profile.getBoolean("enableSMB_EvenOn_OddOff_always"), + iob_threshold_percent = determineBasalResult.profile.getInt("iob_threshold_percent"), + profile_percentage = determineBasalResult.profile.getInt("profile_percentage") + ) + val meatData = MealData( + carbs = determineBasalResult.mealData.getDouble("carbs"), + mealCOB = determineBasalResult.mealData.getDouble("mealCOB"), + slopeFromMaxDeviation = determineBasalResult.mealData.getDouble("slopeFromMaxDeviation"), + slopeFromMinDeviation = determineBasalResult.mealData.getDouble("slopeFromMinDeviation"), + lastBolusTime = determineBasalResult.mealData.getLong("lastBolusTime"), + lastCarbTime = determineBasalResult.mealData.getLong("lastCarbTime") + ) + val resultKt = determineBasalAutoISF.determine_basal( + glucose_status = glucoseStatus, + currenttemp = currentTemp, + iob_data_array = iobData.toTypedArray(), + profile = profile, + autosens_data = autosensData, + meal_data = meatData, + microBolusAllowed = determineBasalResult.microBolusAllowed, + currentTime = currentTime, + flatBGsDetected = determineBasalResult.flatBGsDetected, + dynIsfMode = false + ) + val endKt = System.currentTimeMillis() + ktTime += (endKt - startKt) +// + // aapsLogger.info(LTag.APS, resultKt.toString()) +// + // aapsLogger.debug(LTag.APS, result?.json()?.getString("reason") ?: "") + // aapsLogger.debug(LTag.APS, resultKt.reason.toString()) + aapsLogger.debug(LTag.APS, "File: $filename") +// // assertThat(resultKt.reason.toString()).isEqualTo(result?.json?.getString("reason")) + assertThat(resultKt.tick ?: "").isEqualTo(result?.json()?.optString("tick")) + assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) + assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("targetBG")) + assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result?.json()?.optDouble("insulinReq")) + assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) + assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) + assertThat(resultKt.units ?: Double.NaN).isEqualTo(result?.json()?.optDouble("units")) + assertThat(resultKt.sensitivityRatio ?: Double.NaN).isEqualTo(result?.json()?.optDouble("sensitivityRatio")) + assertThat(resultKt.duration ?: 0).isEqualTo(result?.json()?.optInt("duration")) + assertThat(resultKt.rate ?: Double.NaN).isEqualTo(result?.json()?.optDouble("rate")) + assertThat(resultKt.COB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("COB")) + assertThat(resultKt.IOB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("IOB")) + } + enum class TestSource { ASSET, FILE } data class TestFile(val source: TestSource, val path: String, val name: String) diff --git a/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPSSMBAutoISF/DetermineBasalAdapterAutoISFJS.kt b/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPSSMBAutoISF/DetermineBasalAdapterAutoISFJS.kt new file mode 100644 index 00000000000..8c6fdb92a5f --- /dev/null +++ b/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPSSMBAutoISF/DetermineBasalAdapterAutoISFJS.kt @@ -0,0 +1,352 @@ +package app.aaps.plugins.aps.openAPSSMBAutoISF + +import androidx.annotation.VisibleForTesting +//import app.aaps.plugins.aps.openAPSAutoISF. +import app.aaps.core.data.aps.SMBDefaults +import app.aaps.core.interfaces.aps.IobTotal +import app.aaps.core.data.model.GlucoseUnit +import app.aaps.core.interfaces.aps.APSResult +import app.aaps.core.interfaces.aps.DetermineBasalAdapter +import app.aaps.core.interfaces.aps.GlucoseStatus +import app.aaps.core.interfaces.aps.MealData +import app.aaps.core.interfaces.constraints.ConstraintsChecker +import app.aaps.core.interfaces.db.ProcessedTbrEbData +import app.aaps.core.interfaces.logging.AAPSLogger +import app.aaps.core.interfaces.logging.LTag +import app.aaps.core.interfaces.plugin.ActivePlugin +import app.aaps.core.interfaces.profile.Profile +import app.aaps.core.interfaces.profile.ProfileFunction +import app.aaps.core.objects.profile.ProfileSealed +import app.aaps.core.interfaces.sharedPreferences.SP +import app.aaps.core.interfaces.utils.DateUtil +import app.aaps.core.keys.BooleanKey +import app.aaps.core.keys.DoubleKey +import app.aaps.core.keys.IntKey +import app.aaps.core.keys.Preferences +import app.aaps.core.keys.UnitDoubleKey +import app.aaps.core.objects.extensions.convertToJSONArray +import app.aaps.core.objects.extensions.convertedToAbsolute +import app.aaps.core.objects.extensions.getPassedDurationToTimeInMinutes +import app.aaps.core.objects.extensions.plannedRemainingMinutes +import app.aaps.plugins.aps.R +import app.aaps.plugins.aps.logger.LoggerCallback +import app.aaps.plugins.aps.openAPSSMB.DetermineBasalResultSMBFromJS +import app.aaps.plugins.aps.utils.ScriptReader +import dagger.android.HasAndroidInjector +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import org.mozilla.javascript.Context +import org.mozilla.javascript.Function +import org.mozilla.javascript.NativeJSON +import org.mozilla.javascript.NativeObject +import org.mozilla.javascript.RhinoException +import org.mozilla.javascript.Scriptable +import org.mozilla.javascript.ScriptableObject +import org.mozilla.javascript.Undefined +import java.io.IOException +import java.lang.reflect.InvocationTargetException +import java.nio.charset.StandardCharsets +import javax.inject.Inject + +class DetermineBasalAdapterAutoISFJS(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapter { + + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var constraintChecker: ConstraintsChecker + @Inject lateinit var sp: SP + @Inject lateinit var preferences: Preferences + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var processedTbrEbData: ProcessedTbrEbData + @Inject lateinit var activePlugin: ActivePlugin + @Inject lateinit var dateUtil: DateUtil + + @VisibleForTesting var profile = JSONObject() + @VisibleForTesting var glucoseStatus = JSONObject() + @VisibleForTesting var iobData: JSONArray? = null + @VisibleForTesting var mealData = JSONObject() + @VisibleForTesting var currentTemp = JSONObject() + @VisibleForTesting var autosensData = JSONObject() + @VisibleForTesting var microBolusAllowed = false + @VisibleForTesting var smbAlwaysAllowed = false + @VisibleForTesting var currentTime: Long = 0 + @VisibleForTesting var flatBGsDetected = false + + override var currentTempParam: String? = null + override var iobDataParam: String? = null + override var glucoseStatusParam: String? = null + override var profileParam: String? = null + override var mealDataParam: String? = null + override var scriptDebug = "" + + @Suppress("SpellCheckingInspection") + override fun json(): JSONObject = JSONObject().apply { + put("glucoseStatus", glucoseStatus) + put("currenttemp", currentTemp) + put("iob_data", iobData) + put("profile", profile) + put("autosens_data", autosensData) + put("meal_data", mealData) + put("microBolusAllowed", microBolusAllowed) + put("reservoir_data", null) + put("currentTime", currentTime) + put("flatBGsDetected", flatBGsDetected) + } + + @Suppress("SpellCheckingInspection") + override operator fun invoke(): APSResult? { + aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal <<<") + aapsLogger.debug(LTag.APS, "Glucose status: " + glucoseStatus.toString().also { glucoseStatusParam = it }) + aapsLogger.debug(LTag.APS, "IOB data: " + iobData.toString().also { iobDataParam = it }) + aapsLogger.debug(LTag.APS, "Current temp: " + currentTemp.toString().also { currentTempParam = it }) + aapsLogger.debug(LTag.APS, "Profile: " + profile.toString().also { profileParam = it }) + aapsLogger.debug(LTag.APS, "Meal data: " + mealData.toString().also { mealDataParam = it }) + aapsLogger.debug(LTag.APS, "Autosens data: $autosensData") + aapsLogger.debug(LTag.APS, "Reservoir data: " + "undefined") + aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") + aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed") + aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime") + aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") + var determineBasalResultSMB: APSResult? = null //var determineBasalResultSMB: DetermineBasalResultSMBFromJS? = null + val rhino = Context.enter() + val scope: Scriptable = rhino.initStandardObjects() + // Turn off optimization to make Rhino Android compatible + rhino.optimizationLevel = -1 + try { + + //register logger callback for console.log and console.error + ScriptableObject.defineClass(scope, LoggerCallback::class.java) + val myLogger = rhino.newObject(scope, "LoggerCallback", null) + scope.put("console2", scope, myLogger) + rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null) + + //set module parent + rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null) + rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null) + rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null) + + //generate functions "determine_basal" and "setTempBasal" + rhino.evaluateString(scope, readFile("OpenAPSSMBAutoISF/determine-basal.js"), "JavaScript", 0, null) + rhino.evaluateString(scope, readFile("OpenAPSSMB/basal-set-temp.js"), "setTempBasal.js", 0, null) + val determineBasalObj = scope["determine_basal", scope] + val setTempBasalFunctionsObj = scope["tempBasalFunctions", scope] + + //call determine-basal + if (determineBasalObj is Function && setTempBasalFunctionsObj is NativeObject) { + + //prepare parameters + val params = arrayOf( + makeParam(glucoseStatus, rhino, scope), + makeParam(currentTemp, rhino, scope), + makeParamArray(iobData, rhino, scope), + makeParam(profile, rhino, scope), + makeParam(autosensData, rhino, scope), + makeParam(mealData, rhino, scope), + setTempBasalFunctionsObj, + java.lang.Boolean.valueOf(microBolusAllowed), + makeParam(null, rhino, scope), // reservoir data as undefined + java.lang.Long.valueOf(currentTime), + java.lang.Boolean.valueOf(flatBGsDetected) + ) + val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject + scriptDebug = LoggerCallback.scriptDebug + + // Parse the jsResult object to a JSON-String + val result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString() + aapsLogger.debug(LTag.APS, "Result: $result") + try { + val resultJson = JSONObject(result) + determineBasalResultSMB = DetermineBasalResultSMBFromJS(injector, resultJson) + } catch (e: JSONException) { + aapsLogger.error(LTag.APS, "Unhandled exception", e) + } + } else { + aapsLogger.error(LTag.APS, "Problem loading JS Functions") + } + } catch (e: IOException) { + aapsLogger.error(LTag.APS, "IOException") + } catch (e: RhinoException) { + aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString()) + } catch (e: IllegalAccessException) { + aapsLogger.error(LTag.APS, e.toString()) + } catch (e: InstantiationException) { + aapsLogger.error(LTag.APS, e.toString()) + } catch (e: InvocationTargetException) { + aapsLogger.error(LTag.APS, e.toString()) + } finally { + Context.exit() + } + glucoseStatusParam = glucoseStatus.toString() + iobDataParam = iobData.toString() + currentTempParam = currentTemp.toString() + profileParam = profile.toString() + mealDataParam = mealData.toString() + return determineBasalResultSMB + } + + @Suppress("SpellCheckingInspection") + override fun setData( + profile: Profile, + maxIob: Double, + maxBasal: Double, + minBg: Double, + maxBg: Double, + targetBg: Double, + basalRate: Double, + iobArray: Array, + glucoseStatus: GlucoseStatus, + mealData: MealData, + autosensDataRatio: Double, + tempTargetSet: Boolean, + microBolusAllowed: Boolean, + uamAllowed: Boolean, + advancedFiltering: Boolean, + flatBGsDetected: Boolean, + tdd1D: Double?, + tdd7D: Double?, + tddLast24H: Double?, + tddLast4H: Double?, + tddLast8to4H: Double? + ) { + val pump = activePlugin.activePump + val pumpBolusStep = pump.pumpDescription.bolusStep + this.profile.put("max_iob", maxIob) + //mProfile.put("dia", profile.getDia()); + this.profile.put("type", "current") + this.profile.put("max_daily_basal", profile.getMaxDailyBasal()) + this.profile.put("max_basal", maxBasal) + this.profile.put("min_bg", minBg) + this.profile.put("max_bg", maxBg) + this.profile.put("target_bg", targetBg) + this.profile.put("carb_ratio", profile.getIc()) + this.profile.put("sens", profile.getIsfMgdl("test")) + this.profile.put("max_daily_safety_multiplier", preferences.get(DoubleKey.ApsMaxDailyMultiplier)) + this.profile.put("current_basal_safety_multiplier", preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier)) + + //mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)); + this.profile.put("high_temptarget_raises_sensitivity", preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens)) + //mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity)); + this.profile.put("low_temptarget_lowers_sensitivity", preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens)) + this.profile.put("sensitivity_raises_target", preferences.get(BooleanKey.ApsSensitivityRaisesTarget)) + this.profile.put("resistance_lowers_target", preferences.get(BooleanKey.ApsResistanceLowersTarget)) + this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments) + this.profile.put("exercise_mode", SMBDefaults.exercise_mode) + this.profile.put("half_basal_exercise_target", preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget)) + this.profile.put("maxCOB", SMBDefaults.maxCOB) + this.profile.put("skip_neutral_temps", pump.setNeutralTempAtFullHour()) + // min_5m_carbimpact is not used within SMB determinebasal + //if (mealData.usedMinCarbsImpact > 0) { + // mProfile.put("min_5m_carbimpact", mealData.usedMinCarbsImpact); + //} else { + // mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact)); + //} + this.profile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap) + this.profile.put("enableUAM", uamAllowed) + this.profile.put("A52_risk_enable", SMBDefaults.A52_risk_enable) + val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) + this.profile.put("SMBInterval", preferences.get(IntKey.ApsMaxSmbFrequency)) + this.profile.put("enableSMB_with_COB", smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithCob)) + this.profile.put("enableSMB_with_temptarget", smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithLowTt)) + this.profile.put("allowSMB_with_high_temptarget", smbEnabled && preferences.get(BooleanKey.ApsUseSmbWithHighTt)) + this.profile.put("enableSMB_always", smbEnabled && preferences.get(BooleanKey.ApsUseSmbAlways) && advancedFiltering) + this.profile.put("enableSMB_after_carbs", smbEnabled && preferences.get(BooleanKey.ApsUseSmbAfterCarbs) && advancedFiltering) + this.profile.put("maxSMBBasalMinutes", preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb)) + this.profile.put("maxUAMSMBBasalMinutes", preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb)) + //set the min SMB amount to be the amount set by the pump. + this.profile.put("bolus_increment", pumpBolusStep) + this.profile.put("carbsReqThreshold", preferences.get(IntKey.ApsCarbsRequestThreshold)) + this.profile.put("current_basal", basalRate) + this.profile.put("temptargetSet", tempTargetSet) + this.profile.put("autosens_max", preferences.get(DoubleKey.AutosensMax)) + // mod use autoisf here + this.profile.put("autoISF_version", "3.0") // was BuildConfig.AUTOISF_VERSION) + this.profile.put("enable_autoISF", preferences.get(BooleanKey.ApsUseAutoIsfWeights)) + this.profile.put("autoISF_max", preferences.get(DoubleKey.ApsAutoIsfMax)) + this.profile.put("autoISF_min", preferences.get(DoubleKey.ApsAutoIsfMin)) + this.profile.put("bgAccel_ISF_weight", preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight)) + this.profile.put("bgBrake_ISF_weight", preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight)) + this.profile.put("enable_pp_ISF_always", preferences.get(BooleanKey.ApsAutoIsfPpAlways)) + this.profile.put("pp_ISF_hours", preferences.get(IntKey.ApsAutoIsfPpIsfHours)) + this.profile.put("pp_ISF_weight", preferences.get(DoubleKey.ApsAutoIsfPpWeight)) + this.profile.put("delta_ISFrange_weight", preferences.get(DoubleKey.ApsAutoIsfDeltaWeight)) + this.profile.put("lower_ISFrange_weight", preferences.get(DoubleKey.ApsAutoIsfLowBgWeight)) + this.profile.put("higher_ISFrange_weight", preferences.get(DoubleKey.ApsAutoIsfHighBgWeight)) + this.profile.put("enable_dura_ISF_with_COB", preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs)) + this.profile.put("dura_ISF_weight", preferences.get(DoubleKey.ApsAutoIsfDuraWeight)) + // include SMB adaptations + this.profile.put("smb_delivery_ratio", preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio)) + this.profile.put("smb_delivery_ratio_min", preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin)) + this.profile.put("smb_delivery_ratio_max", preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax)) + this.profile.put("smb_delivery_ratio_bg_range", preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange)) + this.profile.put("smb_max_range_extension", preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension)) + this.profile.put("enableSMB_EvenOn_OddOff", preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt)) // TT + this.profile.put("enableSMB_EvenOn_OddOff_always", preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt)) // profile + this.profile.put("iob_threshold_percent", preferences.get(IntKey.ApsAutoIsfIobThPercent)) + this.profile.put("profile_percentage", if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100) + if (profileFunction.getUnits() == GlucoseUnit.MMOL) { + this.profile.put("out_units", "mmol/L") + } + val now = System.currentTimeMillis() + val tb = processedTbrEbData.getTempBasalIncludingConvertedExtended(now) + currentTemp.put("temp", "absolute") + currentTemp.put("duration", tb?.plannedRemainingMinutes ?: 0) + currentTemp.put("rate", tb?.convertedToAbsolute(now, profile) ?: 0.0) + // as we have non default temps longer than 30 mintues + if (tb != null) currentTemp.put("minutesrunning", tb.getPassedDurationToTimeInMinutes(now)) + + iobData = iobArray.convertToJSONArray(dateUtil) + this.glucoseStatus.put("glucose", glucoseStatus.glucose) + this.glucoseStatus.put("noise", glucoseStatus.noise) + if (preferences.get(BooleanKey.ApsAlwaysUseShortDeltas)) { + this.glucoseStatus.put("delta", glucoseStatus.shortAvgDelta) + } else { + this.glucoseStatus.put("delta", glucoseStatus.delta) + } + this.glucoseStatus.put("short_avgdelta", glucoseStatus.shortAvgDelta) + this.glucoseStatus.put("long_avgdelta", glucoseStatus.longAvgDelta) + this.glucoseStatus.put("date", glucoseStatus.date) + this.glucoseStatus.put("duraISFminutes", glucoseStatus.duraISFminutes) + this.glucoseStatus.put("duraISFaverage", glucoseStatus.duraISFaverage) + this.glucoseStatus.put("a0", glucoseStatus.a0) + this.glucoseStatus.put("a1", glucoseStatus.a1) + this.glucoseStatus.put("a2", glucoseStatus.a2) + this.glucoseStatus.put("bgAcceleration", glucoseStatus.bgAcceleration) + this.glucoseStatus.put("corrSqu", glucoseStatus.corrSqu) + this.mealData.put("carbs", mealData.carbs) + this.mealData.put("mealCOB", mealData.mealCOB) + this.mealData.put("slopeFromMaxDeviation", mealData.slopeFromMaxDeviation) + this.mealData.put("slopeFromMinDeviation", mealData.slopeFromMinDeviation) + this.mealData.put("lastBolusTime", mealData.lastBolusTime) + this.mealData.put("lastCarbTime", mealData.lastCarbTime) + if (constraintChecker.isAutosensModeEnabled().value()) { + autosensData.put("ratio", autosensDataRatio) + } else { + autosensData.put("ratio", 1.0) + } + this.microBolusAllowed = microBolusAllowed + smbAlwaysAllowed = advancedFiltering + currentTime = now + this.flatBGsDetected = flatBGsDetected + } + + private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any { + return if (jsonObject == null) Undefined.instance + else NativeJSON.parse(rhino, scope, jsonObject.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] } + } + + private fun makeParamArray(jsonArray: JSONArray?, rhino: Context, scope: Scriptable): Any { + return NativeJSON.parse(rhino, scope, jsonArray.toString()) { _: Context?, _: Scriptable?, _: Scriptable?, objects: Array -> objects[1] } + } + + @Throws(IOException::class) private fun readFile(filename: String): String { + val bytes = scriptReader.readFile(filename) + var string = String(bytes, StandardCharsets.UTF_8) + if (string.startsWith("#!/usr/bin/env node")) { + string = string.substring(20) + } + return string + } + + init { + injector.androidInjector().inject(this) + } +} \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt index 06f0fbd0c81..4e5e8150770 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt @@ -1,6 +1,5 @@ package app.aaps.plugins.aps.openAPSSMB -import android.content.Context import android.util.LongSparseArray import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference @@ -53,7 +52,6 @@ import app.aaps.core.objects.extensions.plannedRemainingMinutes import app.aaps.core.objects.extensions.put import app.aaps.core.objects.extensions.store import app.aaps.core.objects.extensions.target -import app.aaps.core.objects.profile.ProfileSealed import app.aaps.core.utils.MidnightUtils import app.aaps.plugins.aps.OpenAPSFragment import app.aaps.plugins.aps.R From 728f4f0a889208326834977b046d086dfd649361 Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 17 Feb 2024 20:57:37 +0100 Subject: [PATCH 09/38] AutoSIF Tests Fix Injection --- app/src/androidTest/kotlin/app/aaps/di/AlgModule.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/androidTest/kotlin/app/aaps/di/AlgModule.kt b/app/src/androidTest/kotlin/app/aaps/di/AlgModule.kt index ec1abd35634..b30be0c8046 100644 --- a/app/src/androidTest/kotlin/app/aaps/di/AlgModule.kt +++ b/app/src/androidTest/kotlin/app/aaps/di/AlgModule.kt @@ -5,6 +5,7 @@ import app.aaps.plugins.aps.openAPSAMA.DetermineBasalAdapterAMAJS import app.aaps.plugins.aps.openAPSAMA.DetermineBasalResultAMAFromJS import app.aaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import app.aaps.plugins.aps.openAPSSMB.DetermineBasalResultSMBFromJS +import app.aaps.plugins.aps.openAPSSMBAutoISF.DetermineBasalAdapterAutoISFJS import app.aaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS import dagger.Module import dagger.android.ContributesAndroidInjector @@ -18,5 +19,6 @@ abstract class AlgModule { @ContributesAndroidInjector abstract fun determineBasalResultAMAInjector(): DetermineBasalResultAMAFromJS @ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS @ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS - @ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS + @ContributesAndroidInjector abstract fun determineBasalAdapterSMBDynamicISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS + @ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterAutoISFJS } \ No newline at end of file From f8f1372d3d60fdb605954c97b71b67220cf1b950 Mon Sep 17 00:00:00 2001 From: Philoul Date: Sun, 18 Feb 2024 11:02:14 +0100 Subject: [PATCH 10/38] AutoSIF Fix duplicate code --- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 102a9919000..561d907a235 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -568,27 +568,24 @@ class DetermineBasalAutoISF @Inject constructor( if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget) { - if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget - || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) { - // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 - // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 - //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); - val c = (halfBasalTarget - normalTarget).toDouble() - if (c * (c + target_bg-normalTarget) <= 0.0) { - sensitivityRatio = profile.autosens_max - } else { - sensitivityRatio = c / (c + target_bg - normalTarget) - // limit sensitivityRatio to profile.autosens_max (1.2x by default) - sensitivityRatio = min(sensitivityRatio, profile.autosens_max) - sensitivityRatio = round(sensitivityRatio, 2) - exercise_ratio = sensitivityRatio - origin_sens = "from TT modifier" - consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") - } + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + val c = (halfBasalTarget - normalTarget).toDouble() + if (c * (c + target_bg-normalTarget) <= 0.0) { + sensitivityRatio = profile.autosens_max } else { - sensitivityRatio = autosens_data.ratio - consoleError.add("Autosens ratio: $sensitivityRatio; ") + sensitivityRatio = c / (c + target_bg - normalTarget) + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = min(sensitivityRatio, profile.autosens_max) + sensitivityRatio = round(sensitivityRatio, 2) + exercise_ratio = sensitivityRatio + origin_sens = "from TT modifier" + consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") } + } else { + sensitivityRatio = autosens_data.ratio + consoleError.add("Autosens ratio: $sensitivityRatio; ") } val iobTH_reduction_ratio = profile.profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; basal = profile.current_basal * sensitivityRatio From 53295f9772162911012ac86665890852a70e1ebe Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 2 Mar 2024 11:46:16 +0100 Subject: [PATCH 11/38] AutoSIF Draft code reorganization 2-in-1 --- .../kotlin/app/aaps/core/keys/BooleanKey.kt | 4 +- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 438 +--------- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 777 +++++++++++++++--- plugins/aps/src/main/res/values/strings.xml | 2 + .../src/main/res/xml/pref_openapsautoisf.xml | 327 -------- 5 files changed, 680 insertions(+), 868 deletions(-) delete mode 100644 plugins/aps/src/main/res/xml/pref_openapsautoisf.xml diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt index 9c668cf5654..73b80f69535 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt @@ -50,7 +50,7 @@ enum class BooleanKey( ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false, defaultedBySM = true), ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false, defaultedBySM = true), ApsAutoIsfSmbOnEvenTt(R.string.key_enableSMB_EvenOn_OddOff, false, defaultedBySM = true), // TempTarget - ApsAutoIsfSmbOnEvenPt(R.string.key_enableSMB_EvenOn_OddOff_always, false, defaultedBySM = true) // profile target + ApsAutoIsfSmbOnEvenPt(R.string.key_enableSMB_EvenOn_OddOff_always, false, defaultedBySM = true), // profile target AutotuneAutoSwitchProfile(R.string.key_autotune_auto, false), AutotuneCategorizeUamAsBasal(R.string.key_autotune_categorize_uam_as_basal, false), @@ -59,5 +59,5 @@ enum class BooleanKey( AutotuneAdditionalLog(R.string.key_autotune_additional_log, false), SmsAllowRemoteCommands(R.string.key_smscommunicator_remote_commands_allowed, false), - SmsReportPumpUnreachable(R.string.key_smscommunicator_report_pump_unreachable, true), + SmsReportPumpUnreachable(R.string.key_smscommunicator_report_pump_unreachable, true) } \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 561d907a235..b70fe5fc43b 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -1,12 +1,12 @@ package app.aaps.plugins.aps.openAPSAutoISF import app.aaps.core.interfaces.aps.APSResult -import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData +import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.profile.ProfileUtil @@ -59,7 +59,7 @@ class DetermineBasalAutoISF @Inject constructor( //if (profile.out_units === "mmol/L") round(value / 18, 1).toFixed(1); //else Math.round(value); - fun enable_smb(profile: AutoISFProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { + fun enable_smb(profile: OapsProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { // disable SMB when a high temptarget is set if (!microBolusAllowed) { consoleError.add("SMB disabled (!microBolusAllowed)") @@ -104,10 +104,10 @@ class DetermineBasalAutoISF @Inject constructor( consoleError.add(msg) } - private fun getMaxSafeBasal(profile: AutoISFProfile): Double = + private fun getMaxSafeBasal(profile: OapsProfile): Double = min(profile.max_basal, min(profile.max_daily_safety_multiplier * profile.max_daily_basal, profile.current_basal_safety_multiplier * profile.current_basal)) - fun setTempBasal(_rate: Double, duration: Int, profile: AutoISFProfile, rT: RT, currenttemp: CurrentTemp): RT { + fun setTempBasal(_rate: Double, duration: Int, profile: OapsProfile, rT: RT, currenttemp: CurrentTemp): RT { //var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); val maxSafeBasal = getMaxSafeBasal(profile) @@ -145,356 +145,15 @@ class DetermineBasalAutoISF @Inject constructor( } } - fun loop_smb(microBolusAllowed: Boolean, profile: AutoISFProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double) : String - { - if ( !microBolusAllowed ) { - return "AAPS" // see message in enable_smb - } - if (profile.temptargetSet && profile.enableSMB_EvenOn_OddOff || profile.min_bg==profile.max_bg && profile.enableSMB_EvenOn_OddOff_always && !profile.temptargetSet) { - var target = convert_bg(profile.target_bg) - var msgType: String - var evenTarget: Boolean - var msgUnits: String - var msgTail: String - var msgEven: String - var msg: String - if (profile.temptargetSet) { - msgType= "TempTarget" - } else { - msgType = "profile target" - } - if (profile.out_units == "mmol/L") { - evenTarget = (target.toDouble()*10.0).toInt() % 2 == 0 - msgUnits = "has " - msgTail = "decimal" - } else { - evenTarget = target.toInt() % 2 == 0 - msgUnits = "is " - msgTail = "number" - } - if ( evenTarget ) { - msgEven = "even " - } else { - msgEven = "odd " - } - var iobTHeffective = profile.iob_threshold_percent - if ( !evenTarget ) { - consoleError.add("SMB disabled; $msgType $target $msgUnits $msgEven $msgTail") - consoleError.add("Loop at minimum power") - return "blocked" - } else if ( profile.max_iob==0.0 ) { - consoleError.add("SMB disabled because of max_iob=0") - return "blocked" - } else if (iobTHeffective/100.0 < iob_data_iob/(profile.max_iob*iobTH_reduction_ratio)) { - if (iobTH_reduction_ratio != 1.0) { - consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob*iobTH_reduction_ratio,2)} due to profile % and/or exercise mode") - msg = "effective maxIOB ${round(profile.max_iob*iobTH_reduction_ratio,2)}" - } else { - msg = "maxIOB ${profile.max_iob}" - } - consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is more than $iobTHeffective% of $msg") - consoleError.add("Full Loop capped"); - return "iobTH"; - } else { - consoleError.add("SMB enabled; $msgType $target $msgUnits $msgEven $msgTail") - if (profile.target_bg<100) { // indirect assessment; later set it in GUI - consoleError.add("Loop at full power") - return "fullLoop" // even number - } else { - consoleError.add("Loop at medium power") - return "enforced" // even number - } - } - } - consoleError.add("Full Loop disabled") - return "AAPS" // leave it to standard AAPS - } - - fun interpolate(xdata: Double, profile: AutoISFProfile, type: String): Double - { // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... - val polyX: Array - val polyY: Array - if (type == "bg") { - // ... <---------------------- glucose ----------------------> - polyX = arrayOf(50.0, 60.0, 80.0, 90.0, 100.0, 110.0, 150.0, 180.0, 200.0) - polyY = arrayOf(-0.5, -0.5, -0.3, -0.2, 0.0, 0.0, 0.5, 0.7, 0.7) - } else { - // ... <------- delta --------> - polyX = arrayOf(2.0, 7.0, 12.0, 16.0, 20.0) - polyY = arrayOf(0.0, 0.0, 0.4, 0.7, 0.7) - } - val polymax: Int = polyX.size-1 - var step = polyX[0] - var sVal = polyY[0] - var stepT= polyX[polymax] - var sValold = polyY[polymax] - - var newVal = 1.0 - var lowVal = 1.0 - var topVal : Double - var lowX: Double - var topX: Double - var myX: Double - var lowLabl = step - - if (step > xdata) { - // extrapolate backwards - stepT = polyX[1] - sValold = polyY[1] - lowVal = sVal - topVal = sValold - lowX = step - topX = stepT - myX = xdata - newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) - } else if (stepT < xdata) { - // extrapolate forwards - step = polyX[polymax-1] - sVal = polyY[polymax-1] - lowVal = sVal - topVal = sValold - lowX = step - topX = stepT - myX = xdata - newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) - } else { - // interpolate - for ( i: Int in 0..polymax) { - step = polyX[i] - sVal = polyY[i] - if (step == xdata) { - newVal = sVal - break - } else if (step > xdata) { - topVal = sVal - lowX= lowLabl - myX = xdata - topX= step - newVal = lowVal + (topVal-lowVal)/(topX-lowX)*(myX-lowX) - break - } - lowVal = sVal - lowLabl= step - } - } - if (type == "delta") {newVal = newVal * profile.delta_ISFrange_weight} // delta range - else if ( xdata>100) {newVal = newVal * profile.higher_ISFrange_weight} // higher BG range - else {newVal = newVal * profile.lower_ISFrange_weight} // lower BG range - return newVal - } - - fun withinISFlimits( - liftISF: Double, minISFReduction: Double, maxISFReduction: Double, sensitivityRatio: Double, origin_sens: String, profile: AutoISFProfile, - high_temptarget_raises_sensitivity: Boolean, target_bg: Double, normalTarget: Int): Double { - var liftISFlimited: Double = liftISF - if ( liftISF < minISFReduction ) { - consoleError.add("weakest autoISF factor ${round(liftISF,2)} limited by autoISF_min $minISFReduction") - liftISFlimited = minISFReduction - } else if ( liftISF > maxISFReduction ) { - consoleError.add("strongest autoISF factor ${round(liftISF,2)} limited by autoISF_max $maxISFReduction") - liftISFlimited = maxISFReduction - } - var finalISF: Double - var origin_sens_final = origin_sens - if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget ) { - finalISF = liftISFlimited * sensitivityRatio - origin_sens_final = " including exercise mode impact" - } else if ( liftISFlimited >= 1 ) { - finalISF = max(liftISFlimited, sensitivityRatio) - } else { - finalISF = min(liftISFlimited, sensitivityRatio) - } - consoleError.add("final ISF factor is ${round(finalISF,2)}" + origin_sens_final) - consoleError.add("----------------------------------") - consoleError.add("end autoISF") - consoleError.add("----------------------------------") - return finalISF - } - - fun determine_varSMBratio(profile: AutoISFProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double - { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target - var smb_delivery_ratio_bg_range = profile.smb_delivery_ratio_bg_range - if ( smb_delivery_ratio_bg_range<10 ) { smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 } // was in mmol/l - var fix_SMB: Double = profile.smb_delivery_ratio - var lower_SMB = min(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max) - var higher_SMB = max(profile.smb_delivery_ratio_min, profile.smb_delivery_ratio_max) - var higher_bg = target_bg + smb_delivery_ratio_bg_range - var new_SMB: Double = fix_SMB - if ( smb_delivery_ratio_bg_range > 0 ) { - new_SMB = lower_SMB + (higher_SMB-lower_SMB)*(bg-target_bg) / smb_delivery_ratio_bg_range - new_SMB = max(lower_SMB, min(higher_SMB, new_SMB)) // cap if outside target_bg--higher_bg - } - if ( loop_wanted_smb=="fullLoop") { // go for max impactError.add("SMB delivery ratio set to ${max(fix_SMB, new_SMB)} as max of fixed and interpolated values") - return max(fix_SMB, new_SMB) - } - - if ( profile.smb_delivery_ratio_bg_range==0.0) { // deactivated in SMB extended menu - consoleError.add("SMB delivery ratio set to fixed value $fix_SMB") - return fix_SMB - } - if (bg <= target_bg) { - consoleError.add("SMB delivery ratio limited by minimum value $lower_SMB") - return lower_SMB - } - if (bg >= higher_bg) { - consoleError.add("SMB delivery ratio limited by maximum value $higher_SMB") - return higher_SMB - } - consoleError.add("SMB delivery ratio set to interpolated value $new_SMB") - return new_SMB - } - - fun autoISF( - sens: Double, origin_sens: String, target_bg: Double, profile: AutoISFProfile, glucose_status: GlucoseStatus, meal_data: MealData, currentTime: Long, - sensitivityRatio: Double, loop_wanted_smb: String, high_temptarget_raises_sensitivity: Boolean, normalTarget: Int): Double { - if ( !profile.enable_autoISF) { - consoleError.add("autoISF disabled in Preferences") - consoleError.add("----------------------------------") - consoleError.add("end autoISF") - consoleError.add("----------------------------------") - return sens - } - var dura05: Double? = glucose_status.duraISFminutes - var avg05: Double? = glucose_status.duraISFaverage - var maxISFReduction: Double = profile.autoISF_max - var sens_modified = false - var pp_ISF = 1.0 - var delta_ISF = 1.0 - var acce_ISF = 1.0 - var acce_weight: Double = 1.0 - var bg_off = target_bg+10.0 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 - - // calculate acce_ISF from bg acceleration and adapt ISF accordingly - var fit_corr: Double = glucose_status.corrSqu - var bg_acce: Double = glucose_status.bgAcceleration - if (glucose_status.a2 !=0.0 && fit_corr>=0.9) { - var minmax_delta: Double = - glucose_status.a1/2/glucose_status.a2 * 5 // back from 5min block to 1 min - var minmax_value: Double = round(glucose_status.a0 - minmax_delta*minmax_delta/25*glucose_status.a2, 1) - minmax_delta = round(minmax_delta, 1) - if (minmax_delta>0 && bg_acce<0) { - consoleError.add("Parabolic fit extrapolates a maximum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") - } else if (minmax_delta>0 && bg_acce>0.0) { - - consoleError.add("Parabolic fit extrapolates a minimum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") - if (minmax_delta<=30 && minmax_value 0 ) { - if ( bg_acce>1) { cap_weight = 0.5 } // halve the effect below target - acce_weight = profile.bgBrake_ISF_weight - } else if ( bg_acce < 0 ) { - acce_weight = profile.bgAccel_ISF_weight - } - } else if ( acce_weight==1.0) { // above target acce goes away from target - if ( bg_acce < 0.0 ) { - acce_weight = profile.bgBrake_ISF_weight - } else if ( bg_acce > 0.0 ) { - acce_weight = profile.bgAccel_ISF_weight - } - } - acce_ISF = 1.0 + bg_acce * cap_weight * acce_weight * fit_share - consoleError.add("acce_ISF adaptation is ${round(acce_ISF,2)}") - if ( acce_ISF != 1.0 ) { - sens_modified = true - } - } - - val bg_ISF = 1 + interpolate(100-bg_off, profile, "bg") - consoleError.add("bg_ISF adaptation is ${round(bg_ISF,2)}") - var liftISF = 1.0 - var final_ISF = 1.0 - if (bg_ISF<1.0) { - liftISF = min(bg_ISF, acce_ISF) - if ( acce_ISF>1.0 ) { - liftISF = bg_ISF * acce_ISF // bg_ISF could become > 1 now - consoleError.add("bg_ISF adaptation lifted to ${round(liftISF,2)} as bg accelerates already") - } - final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget) - return min(720.0, round(profile.sens / final_ISF, 1)) // observe ISF maximum of 720(?) - } else if ( bg_ISF > 1.0 ) { - sens_modified = true - } - - var bg_delta = glucose_status.delta - var deltaType: String - if (profile.enable_pp_ISF_always || profile.pp_ISF_hours >= (currentTime - meal_data.lastCarbTime) / 1000/3600) { - deltaType = "pp" - } else { - deltaType = "delta" - } - if (bg_off > 0.0) { - consoleError.add(deltaType+"_ISF adaptation by-passed as average glucose < $target_bg+10") - } else if (glucose_status.shortAvgDelta<0) { - consoleError.add(deltaType+"_ISF adaptation by-passed as no rise or too short lived") - } else if (deltaType == "pp") { - pp_ISF = 1.0 + max(0.0, bg_delta * profile.pp_ISF_weight) - consoleError.add("pp_ISF adaptation is ${round(pp_ISF,2)}") - if (pp_ISF != 1.0) { - sens_modified = true - } - - } else { - delta_ISF = interpolate(bg_delta, profile, "delta"); - // mod V14d: halve the effect below target_bg+30 - if ( bg_off > -20.0 ) { - delta_ISF = 0.5 * delta_ISF - } - delta_ISF = 1.0 + delta_ISF - consoleError.add("delta_ISF adaptation is ${round(delta_ISF,2)}") - - if (delta_ISF != 1.0) { - sens_modified = true - } - } - - var dura_ISF: Double = 1.0 - val weightISF: Double? = profile.dura_ISF_weight - if (meal_data.mealCOB>0 && !profile.enable_dura_ISF_with_COB) { - consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB,1)}") - } else if (dura05!!<10.0) { - consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05"); - } else if (avg05!! <= target_bg) { - consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") - } else { - // fight the resistance at high levels - val dura05Weight = dura05 / 60 - var avg05Weight = weightISF!! / target_bg - dura_ISF += dura05Weight*avg05Weight*(avg05-target_bg) - sens_modified = true - consoleError.add("dura_ISF adaptation is ${round(dura_ISF,2)} because ISF ${round(sens,1)} did not do it for ${round(dura05,1)}m") - } - if ( sens_modified ) { - liftISF = max(dura_ISF, max(bg_ISF, max(delta_ISF, max(acce_ISF, pp_ISF)))) - if ( acce_ISF < 1.0 ) { // 13.JAN.2022 brakes on for otherwise stronger or stable ISF - consoleError.add("strongest autoISF factor ${round(liftISF,2)} weakened to ${round(liftISF*acce_ISF,2)} as bg decelerates already") - liftISF = liftISF * acce_ISF // brakes on for otherwise stronger or stable ISF - } // brakes on for otherwise stronger or stable ISF - final_ISF = withinISFlimits(liftISF, profile.autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, profile, high_temptarget_raises_sensitivity, target_bg, normalTarget) - return round(profile.sens / final_ISF, 1) - } - consoleError.add("----------------------------------") - consoleError.add("end autoISF") - consoleError.add("----------------------------------") - return sens // nothing changed - } fun determine_basal( - glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: AutoISFProfile, autosens_data: AutosensResult, meal_data: MealData, - microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean + glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, + microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean, loop_wanted_smb: String, profile_percentage: Int, smb_ratio: Double, + smb_max_range_extension: Double, iob_threshold_percent: Int, auto_isf_console: MutableList ): RT { consoleError.clear() consoleLog.clear() - var rT = RT( algorithm = APSResult.Algorithm.SMB, runningDynamicIsf = dynIsfMode, @@ -558,7 +217,7 @@ class DetermineBasalAutoISF @Inject constructor( var min_bg = profile.min_bg var max_bg = profile.max_bg - var sensitivityRatio: Double = 1.0 + var sensitivityRatio = 1.0 var origin_sens = "" var exercise_ratio = 1.0 val high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity @@ -566,8 +225,16 @@ class DetermineBasalAutoISF @Inject constructor( // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%), 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) val halfBasalTarget = profile.half_basal_exercise_target + if (dynIsfMode) { + consoleError.add("---------------------------------------------------------") + consoleError.add(" Auto ISF 3.0") + consoleError.add("---------------------------------------------------------") + consoleError.addAll(auto_isf_console) + } + if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget - || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget) { + || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget + ) { // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); @@ -587,7 +254,7 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = autosens_data.ratio consoleError.add("Autosens ratio: $sensitivityRatio; ") } - val iobTH_reduction_ratio = profile.profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; + val iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; basal = profile.current_basal * sensitivityRatio basal = round_basal(basal) if (basal != profile_current_basal) @@ -619,7 +286,6 @@ class DetermineBasalAutoISF @Inject constructor( val iob_data = iobArray[0] val tick: String - tick = if (glucose_status.delta > -0.5) { "+" + round(glucose_status.delta) } else { @@ -629,51 +295,20 @@ class DetermineBasalAutoISF @Inject constructor( val minAvgDelta = min(glucose_status.shortAvgDelta, glucose_status.longAvgDelta) val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) - //var sens = - //if (dynIsfMode) profile.variable_sens - //else { + val sens = + if (dynIsfMode) profile.variable_sens + else { val profile_sens = round(profile.sens, 1) val adjusted_sens = round(profile.sens / sensitivityRatio, 1) if (adjusted_sens != profile_sens) { - consoleError.add("ISF from $profile_sens to $adjusted_sens") + consoleLog.add("ISF from $profile_sens to $adjusted_sens") } else { - consoleError.add("ISF unchanged: $adjusted_sens") + consoleLog.add("ISF unchanged: $adjusted_sens") } - var sens = adjusted_sens + adjusted_sens //console.log(" (autosens ratio "+sensitivityRatio+")"); - //} - consoleError.add("CR:${profile.carb_ratio}") - - var loop_wanted_smb: String - var enableSMB = false - if (!profile.enable_autoISF) { - loop_wanted_smb = "AAPS" - enableSMB = enable_smb( - profile, - microBolusAllowed, - meal_data, - target_bg - ) - } else { // in autoIsfMode - consoleError.add("----------------------------------") - consoleError.add("start autoISF ${profile.autoISF_version}") // fit onto narrow screens - consoleError.add("----------------------------------") - - loop_wanted_smb = loop_smb(microBolusAllowed, profile, iob_data.iob, iobTH_reduction_ratio) - if (microBolusAllowed && loop_wanted_smb != "AAPS") { - if (loop_wanted_smb == "enforced" || loop_wanted_smb == "fullLoop") { // otherwise FL switched SMB off - enableSMB = true - } - } else { - enableSMB = enable_smb( - profile, - microBolusAllowed, - meal_data, - target_bg - ) } - sens = autoISF(sens, origin_sens, target_bg, profile, glucose_status, meal_data, currentTime, sensitivityRatio, loop_wanted_smb, high_temptarget_raises_sensitivity, normalTarget) - } + consoleError.add("CR:${profile.carb_ratio}") //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone val bgi = round((-iob_data.activity * sens * 5), 2) @@ -758,7 +393,7 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = sensitivityRatio, // autosens ratio (fraction of normal basal) consoleLog = consoleLog, consoleError = consoleError, - variable_sens = sens // if (dynIsfMode) profile.variable_sens else sens + variable_sens = profile.variable_sens ) // generate predicted future BGs based on IOB, COB, and current absorption rate @@ -774,7 +409,7 @@ class DetermineBasalAutoISF @Inject constructor( ZTpredBGs.add(bg) UAMpredBGs.add(bg) - //var enableSMB = enable_smb(profile, microBolusAllowed, meal_data, target_bg) // pulled ahead for autoISF + var enableSMB = if (dynIsfMode) microBolusAllowed else enable_smb(profile, microBolusAllowed, meal_data, target_bg) // pulled ahead for autoISF // enable UAM (if enabled in preferences) val enableUAM = profile.enableUAM @@ -901,15 +536,9 @@ class DetermineBasalAutoISF @Inject constructor( //console.error(iobTick); val predBGI: Double = round((-iobTick.activity * sens * 5), 2) val IOBpredBGI: Double = predBGI - //if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(IOBpredBGs[IOBpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - //else predBGI iobTick.iobWithZeroTemp ?: error("iobTick.iobWithZeroTemp missing") val predZTBGI = round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) - //if (dynIsfMode) round((-iobTick.iobWithZeroTemp!!.activity * (1800 / (profile.TDD * (ln((max(ZTpredBGs[ZTpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - //else round((-iobTick.iobWithZeroTemp!!.activity * sens * 5), 2) val predUAMBGI = predBGI - //if (dynIsfMode) round((-iobTick.activity * (1800 / (profile.TDD * (ln((max(UAMpredBGs[UAMpredBGs.size - 1], 39.0) / profile.insulinDivisor) + 1)))) * 5), 2) - //else predBGI // for IOBpredBGs, predicted deviation impact drops linearly from current deviation down to zero // over 60 minutes (data points every 5m) val predDev: Double = ci * (1 - min(1.0, IOBpredBGs.size / (60.0 / 5.0))) @@ -1268,9 +897,7 @@ class DetermineBasalAutoISF @Inject constructor( // calculate 30m low-temp required to get projected BG up to target // multiply by 2 to low-temp faster for increased hypo safety - var insulinReq = - //if (dynIsfMode) 2 * min(0.0, (eventualBG - target_bg) / future_sens) - 2 * min(0.0, (eventualBG - target_bg) / sens) + var insulinReq = 2 * min(0.0, (eventualBG - target_bg) / sens) insulinReq = round(insulinReq, 2) // calculate naiveInsulinReq based on naive_eventualBG var naiveInsulinReq = min(0.0, (naive_eventualBG - target_bg) / sens) @@ -1400,7 +1027,7 @@ class DetermineBasalAutoISF @Inject constructor( if (microBolusAllowed && enableSMB && bg > threshold) { // never bolus more than maxSMBBasalMinutes worth of basal val mealInsulinReq = round(meal_data.mealCOB / profile.carb_ratio, 3) - val smb_max_range = profile.smb_max_range_extension + val smb_max_range = smb_max_range_extension if (iob_data.iob > mealInsulinReq && iob_data.iob > 0) { consoleError.add("IOB ${iob_data.iob} > COB ${meal_data.mealCOB}; mealInsulinReq = $mealInsulinReq") consoleError.add("profile.maxUAMSMBBasalMinutes: ${profile.maxUAMSMBBasalMinutes} profile.current_basal: ${profile.current_basal}") @@ -1413,18 +1040,17 @@ class DetermineBasalAutoISF @Inject constructor( val roundSMBTo = 1 / profile.bolus_increment //var microBolus: Double var microBolus = Math.floor(Math.min(insulinReq / 2, maxBolus) * roundSMBTo) / roundSMBTo - //if (autoIsfMode) { - val smb_ratio = determine_varSMBratio(profile, bg.toInt(), target_bg, loop_wanted_smb) + if (dynIsfMode) { microBolus = Math.min(insulinReq * smb_ratio, maxBolus) // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun val iobTHtolerance = 130 - val iobTHvirtual = profile.iob_threshold_percent * iobTHtolerance / 10000 * profile.max_iob * iobTH_reduction_ratio + val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000 * profile.max_iob * iobTH_reduction_ratio if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb == "fullLoop" || loop_wanted_smb == "enforced")) { microBolus = iobTHvirtual - iob_data.iob consoleError.add("Full loop capped SMB at ${round(microBolus, 2)} to not exceed $iobTHtolerance% of effective iobTH ${round(iobTHvirtual / iobTHtolerance * 100, 2)}U") } microBolus = Math.floor(microBolus * roundSMBTo) / roundSMBTo - //} + } // calculate a long enough zero temp to eventually correct back up to target val smbTarget = target_bg diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index e7dffa3979d..ed646675503 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -1,18 +1,25 @@ package app.aaps.plugins.aps.openAPSAutoISF +import android.content.Context +import android.content.Intent +import android.net.Uri import android.util.LongSparseArray +import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import androidx.preference.PreferenceScreen import androidx.preference.SwitchPreference import app.aaps.core.data.aps.SMBDefaults import app.aaps.core.data.model.GlucoseUnit -import app.aaps.core.data.plugin.PluginDescription import app.aaps.core.data.plugin.PluginType import app.aaps.core.data.time.T import app.aaps.core.interfaces.aps.APS import app.aaps.core.interfaces.aps.APSResult import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp -import app.aaps.core.interfaces.aps.AutoISFProfile +import app.aaps.core.interfaces.aps.GlucoseStatus +import app.aaps.core.interfaces.aps.MealData +import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck import app.aaps.core.interfaces.configuration.Config import app.aaps.core.interfaces.constraints.Constraint @@ -27,6 +34,7 @@ import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.notifications.Notification import app.aaps.core.interfaces.plugin.ActivePlugin import app.aaps.core.interfaces.plugin.PluginBase +import app.aaps.core.interfaces.plugin.PluginDescription import app.aaps.core.interfaces.profile.Profile import app.aaps.core.interfaces.profile.ProfileFunction import app.aaps.core.interfaces.profile.ProfileUtil @@ -39,9 +47,12 @@ import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.HardLimits import app.aaps.core.interfaces.utils.Round +import app.aaps.core.keys.AdaptiveIntentPreference +import app.aaps.core.keys.AdaptiveSwitchPreference import app.aaps.core.keys.BooleanKey import app.aaps.core.keys.DoubleKey import app.aaps.core.keys.IntKey +import app.aaps.core.keys.IntentKey import app.aaps.core.keys.Preferences import app.aaps.core.keys.UnitDoubleKey import app.aaps.core.objects.aps.DetermineBasalResult @@ -54,6 +65,9 @@ import app.aaps.core.objects.extensions.store import app.aaps.core.objects.extensions.target import app.aaps.core.objects.profile.ProfileSealed import app.aaps.core.utils.MidnightUtils +import app.aaps.core.validators.AdaptiveDoublePreference +import app.aaps.core.validators.AdaptiveIntPreference +import app.aaps.core.validators.AdaptiveUnitPreference import app.aaps.plugins.aps.OpenAPSFragment import app.aaps.plugins.aps.R import app.aaps.plugins.aps.events.EventOpenAPSUpdateGui @@ -65,6 +79,9 @@ import javax.inject.Inject import javax.inject.Singleton import kotlin.math.floor import kotlin.math.ln +import kotlin.math.max +import kotlin.math.min +import kotlin.math.pow @Singleton open class OpenAPSAutoISFPlugin @Inject constructor( @@ -88,7 +105,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val bgQualityCheck: BgQualityCheck, private val uiInteraction: UiInteraction, private val determineBasalAutoISF: DetermineBasalAutoISF, - private val profiler: Profiler, + private val profiler: Profiler ) : PluginBase( PluginDescription() .mainType(PluginType.APS) @@ -96,7 +113,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( .pluginIcon(app.aaps.core.ui.R.drawable.ic_generic_icon) .pluginName(R.string.openaps_auto_isf) .shortName(R.string.autoisf_shortname) - .preferencesId(R.xml.pref_openapsautoisf) + .preferencesId(PluginDescription.PREFERENCE_SCREEN) .preferencesVisibleInSimpleMode(false) .showInList(config.APS) .description(R.string.description_auto_isf), @@ -107,7 +124,31 @@ open class OpenAPSAutoISFPlugin @Inject constructor( override var lastAPSRun: Long = 0 override val algorithm = APSResult.Algorithm.SMB override var lastAPSResult: DetermineBasalResult? = null - override fun supportsDynamicIsf(): Boolean = false //preferences.get(BooleanKey.ApsUseAutoIsfWeights) + private var consoleError = mutableListOf() + + private val autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax) + private val autoISF_min = preferences.get(DoubleKey.ApsAutoIsfMin) + private val bgAccel_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight) + private val bgBrake_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight) + private val enable_pp_ISF_always = preferences.get(BooleanKey.ApsAutoIsfPpAlways) + private val pp_ISF_hours = preferences.get(IntKey.ApsAutoIsfPpIsfHours) + private val pp_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfPpWeight) + private val delta_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfDeltaWeight) + private val lower_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfLowBgWeight) + private val higher_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfHighBgWeight) + private val enable_dura_ISF_with_COB = preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs) + private val dura_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfDuraWeight) + private val smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) + private val smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) + private val smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) + private val smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) + val smbMaxRangeExtension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + private val enableSMB_EvenOn_OddOff = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt) // for TT + private val enableSMB_EvenOn_OddOff_always = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt) // for profile target + val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) + private val exerciseMode = SMBDefaults.exercise_mode + private val highTemptargetRaisesSensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) + override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() @@ -155,7 +196,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val dynIsfCache = LongSparseArray() private fun calculateVariableIsf(timestamp: Long, bg: Double?): Pair { - // Calculate here ISF value with AutoISF algo + // Todo : Calculate here ISF value with AutoISF algo + val profile = profileFunction.getProfile(timestamp) + if (profile == null) return Pair("OFF", null) if (!preferences.get(BooleanKey.ApsUseDynamicSensitivity)) return Pair("OFF", null) val result = persistenceLayer.getApsResultCloseTo(timestamp) if (result?.variableSens != null) { @@ -172,22 +215,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return Pair("HIT", cached) } // no cached result found, let's calculate the value - val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 1, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) - val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(timestamp, 7, allowMissingDays = false))?.data?.totalAmount ?: return Pair("TDD miss", null) - val tddLast24H = tddCalculator.calculateDaily(-24, 0)?.totalAmount ?: return Pair("TDD miss", null) - val tddLast4H = tddCalculator.calculateDaily(-4, 0)?.totalAmount ?: return Pair("TDD miss", null) - val tddLast8to4H = tddCalculator.calculateDaily(-8, -4)?.totalAmount ?: return Pair("TDD miss", null) - val insulinDivisor = when { - activePlugin.activeInsulin.peak > 65 -> 55 // lyumjev peak: 45 - activePlugin.activeInsulin.peak > 50 -> 65 // ultra rapid peak: 55 - else -> 75 // rapid peak: 75 - } - val tddStatus = TddStatus(tdd1D, tdd7D, tddLast24H, tddLast4H, tddLast8to4H) - val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 - val tdd = (tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 - - val sensitivity = Round.roundTo(1800 / (tdd * (ln((glucose / insulinDivisor) + 1))), 0.1) - //aapsLogger.debug("calculateVariableIsf $caller CAL ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $sensitivity") + + val sensitivity = (autoISF(timestamp) ?: 1.0) * profile.getIsfMgdlTimeFromMidnight(MidnightUtils.secondsFromMidnight(timestamp)) dynIsfCache.put(key, sensitivity) if (dynIsfCache.size() > 1000) dynIsfCache.clear() return Pair("CALC", sensitivity) @@ -231,7 +260,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // End of check, start gathering data - val dynIsfMode = false // preferences.get(BooleanKey.ApsUseAutoIsf) no flag yet for AutoISF + val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights) val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() @@ -252,78 +281,30 @@ open class OpenAPSAutoISFPlugin @Inject constructor( maxBg = hardLimits.verifyHardLimits(tempTarget.highTarget, app.aaps.core.ui.R.string.temp_target_high_target, HardLimits.LIMIT_TEMP_MAX_BG[0], HardLimits.LIMIT_TEMP_MAX_BG[1]) targetBg = hardLimits.verifyHardLimits(tempTarget.target(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TEMP_TARGET_BG[0], HardLimits.LIMIT_TEMP_TARGET_BG[1]) } - val insulin = activePlugin.activeInsulin - val insulinDivisor = when { - insulin.peak > 65 -> 55 // rapid peak: 75 - insulin.peak > 50 -> 65 // ultra rapid peak: 55 - else -> 75 // lyumjev peak: 45 - } var autosensResult = AutosensResult() - //val tddStatus: TddStatus? var variableSensitivity = 0.0 - var tdd = 0.0 - if (dynIsfMode) { - // DynamicISF specific - // without these values DynISF doesn't work properly - // Current implementation is fallback to SMB if TDD history is not available. Thus calculated here - val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(1, allowMissingDays = false))?.data?.totalAmount - val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(7, allowMissingDays = false)) - val tddLast24H = tddCalculator.calculateDaily(-24, 0) - val tddLast4H = tddCalculator.calculateDaily(-4, 0)?.totalAmount - val tddLast8to4H = tddCalculator.calculateDaily(-8, -4)?.totalAmount - if (tdd1D == null || tdd7D == null || tddLast4H == null || tddLast8to4H == null || tddLast24H == null) { - uiInteraction.addNotificationValidTo( - Notification.SMB_FALLBACK, dateUtil.now(), - rh.gs(R.string.fallback_smb_no_tdd), Notification.INFO, dateUtil.now() + T.mins(1).msecs() - ) - inputConstraints.copyReasons( - ConstraintObject(false, aapsLogger).also { - it.set(false, rh.gs(R.string.fallback_smb_no_tdd), this) - } - ) - inputConstraints.copyReasons( - ConstraintObject(false, aapsLogger).apply { set(true, "tdd1D=$tdd1D tdd7D=${tdd7D?.data?.totalAmount} tddLast4H=$tddLast4H tddLast8to4H=$tddLast8to4H tddLast24H=${tddLast24H?.totalAmount}", this) } - ) - } else { - uiInteraction.dismissNotification(Notification.SMB_FALLBACK) - //tddStatus = TddStatus(tdd1D, tdd7D.data.totalAmount, tddLast24H.totalAmount, tddLast4H, tddLast8to4H) - //val tddWeightedFromLast8H = ((1.4 * tddStatus.tddLast4H) + (0.6 * tddStatus.tddLast8to4H)) * 3 - //tdd = ((tddWeightedFromLast8H * 0.33) + (tddStatus.tdd7D * 0.34) + (tddStatus.tdd1D * 0.33)) * preferences.get(IntKey.ApsDynIsfAdjustmentFactor) / 100.0 - variableSensitivity = Round.roundTo(1800 / (tdd * (ln((glucoseStatus.glucose / insulinDivisor) + 1))), 0.1) - - // Compare insulin consumption of last 24h with last 7 days average profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 - - val tddRatio = if (preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) tddLast24H.totalAmount / tdd7D.data.totalAmount else 1.0 - // Because consumed carbs affects total amount of insulin compensate final ratio by consumed carbs ratio - // take only 60% (expecting 40% basal). We cannot use bolus/total because of SMBs - val carbsRatio = if ( - preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity) && - tddLast24H.carbs != 0.0 && - tdd7D.data.carbs != 0.0 && - tdd7D.allDaysHaveCarbs - ) ((tddLast24H.carbs / tdd7D.data.carbs - 1.0) * 0.6) + 1.0 else 1.0 - autosensResult = AutosensResult( - ratio = tddRatio / carbsRatio, - ratioFromTdd = tddRatio, - ratioFromCarbs = carbsRatio - ) - } - } else { - if (constraintsChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") - if (autosensData == null) { - rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) - return - } - autosensResult = autosensData.autosensResult - } else autosensResult.sensResult = "autosens disabled" - } + val sens = profile.getIsfMgdl("OpenAPSAutoISFPlugin") + if (constraintsChecker.isAutosensModeEnabled().value()) { + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") + if (autosensData == null) { + rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) + return + } + autosensResult = autosensData.autosensResult + } else autosensResult.sensResult = "autosens disabled" val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() + val iobData = iobArray[0] + val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 + var microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() - val autoisfProfile = AutoISFProfile( + if (dynIsfMode) { + consoleError = mutableListOf() + variableSensitivity = autoISF(now) ?: 1.0 + } + val oapsProfile = OapsProfile( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used max_iob = constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), @@ -333,12 +314,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( max_bg = maxBg, target_bg = targetBg, carb_ratio = profile.getIc(), - sens = profile.getIsfMgdl("OpenAPSAutoISFPlugin"), + sens = sens, autosens_adjust_targets = false, // not used max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), - high_temptarget_raises_sensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens), //was false, + high_temptarget_raises_sensitivity = exerciseMode || highTemptargetRaisesSensitivity, //was false, low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), @@ -364,59 +345,48 @@ open class OpenAPSAutoISFPlugin @Inject constructor( temptargetSet = isTempTarget, autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", - //variable_sens = 47.11, //variableSensitivity, - //insulinDivisor = 0, - //TDD = 0.0, - autoISF_version = "3.0", // was BuildConfig.AUTOISF_VERSION) - enable_autoISF = preferences.get(BooleanKey.ApsUseAutoIsfWeights), - autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax), - autoISF_min = preferences.get(DoubleKey.ApsAutoIsfMin), - bgAccel_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight), - bgBrake_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight), - enable_pp_ISF_always = preferences.get(BooleanKey.ApsAutoIsfPpAlways), - pp_ISF_hours = preferences.get(IntKey.ApsAutoIsfPpIsfHours), - pp_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfPpWeight), - delta_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfDeltaWeight), - lower_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfLowBgWeight), - higher_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfHighBgWeight), - enable_dura_ISF_with_COB = preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs), - dura_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfDuraWeight), - smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio), - smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin), - smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax), - smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange), - smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension), - enableSMB_EvenOn_OddOff = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt), // for TT - enableSMB_EvenOn_OddOff_always = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt), // for profile target - iob_threshold_percent = preferences.get(IntKey.ApsAutoIsfIobThPercent), - profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 + variable_sens = variableSensitivity, //variableSensitivity, + insulinDivisor = 0, + TDD = 0.0 ) - - val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() + val exercise_ratio = 1.0 + //todo calculate exercice ratio + val iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio; // later: * activityRatio; + val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, iobTH_reduction_ratio) + if (dynIsfMode) + microBolusAllowed = microBolusAllowed && loopWantedSmb != "AAPS" && (loopWantedSmb == "enforced" || loopWantedSmb == "fullLoop") val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT + val target_bg = (minBg + maxBg) / 2 + val smbRatio = determine_varSMBratio(oapsProfile, glucoseStatus.glucose.toInt(), target_bg, loopWantedSmb) - aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal SMB <<<") + aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AutoISF <<<") aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") aapsLogger.debug(LTag.APS, "Current temp: $currentTemp") aapsLogger.debug(LTag.APS, "IOB data: ${iobArray.joinToString()}") - aapsLogger.debug(LTag.APS, "Profile: $autoisfProfile") + aapsLogger.debug(LTag.APS, "Profile: $oapsProfile") aapsLogger.debug(LTag.APS, "Autosens data: $autosensResult") aapsLogger.debug(LTag.APS, "Meal data: $mealData") aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") - aapsLogger.debug(LTag.APS, "DynIsfMode: $dynIsfMode") + aapsLogger.debug(LTag.APS, "AutoIsfMode: $dynIsfMode") determineBasalAutoISF.determine_basal( glucose_status = glucoseStatus, currenttemp = currentTemp, iob_data_array = iobArray, - profile = autoisfProfile, + profile = oapsProfile, autosens_data = autosensResult, meal_data = mealData, microBolusAllowed = microBolusAllowed, currentTime = now, flatBGsDetected = flatBGsDetected, - dynIsfMode = dynIsfMode + dynIsfMode = dynIsfMode, + loop_wanted_smb = loopWantedSmb, + profile_percentage = profile_percentage, + smb_ratio = smbRatio, + smb_max_range_extension = smbMaxRangeExtension, + iob_threshold_percent = iobThresholdPercent, + auto_isf_console = consoleError ).also { val determineBasalResult = DetermineBasalResult(injector, it) // Preserve input data @@ -425,7 +395,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( determineBasalResult.iobData = iobArray determineBasalResult.glucoseStatus = glucoseStatus determineBasalResult.currentTemp = currentTemp - determineBasalResult.autoIsfProfile = autoisfProfile + determineBasalResult.oapsProfile = oapsProfile determineBasalResult.mealData = mealData lastAPSResult = determineBasalResult lastAPSRun = now @@ -487,15 +457,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } override fun isAutosensModeEnabled(value: Constraint): Constraint { - // if (preferences.get(BooleanKey.ApsUseAutoIsf)) { - // // DynISF mode - // if (!preferences.get(BooleanKey.ApsDynIsfAdjustSensitivity)) - // value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) - // } else { - // SMB mode - val enabled = preferences.get(BooleanKey.ApsUseAutosens) - if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) - // } + val enabled = preferences.get(BooleanKey.ApsUseAutosens) + if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this) return value } @@ -509,4 +472,552 @@ open class OpenAPSAutoISFPlugin @Inject constructor( .store(BooleanKey.ApsUseDynamicSensitivity, preferences, rh) .store(IntKey.ApsDynIsfAdjustmentFactor, preferences, rh) } + + // Rounds value to 'digits' decimal places + // different for negative numbers fun round(value: Double, digits: Int): Double = BigDecimal(value).setScale(digits, RoundingMode.HALF_EVEN).toDouble() + fun round(value: Double, digits: Int): Double { + if (value.isNaN()) return Double.NaN + val scale = 10.0.pow(digits.toDouble()) + return Math.round(value * scale) / scale + } + + fun convert_bg(value: Double): String = + profileUtil.fromMgdlToStringInUnits(value).replace("-0.0", "0.0") + + fun autoISF(currentTime: Long): Double? { + //origin_sens: String, oapsProfile: OapsProfile, sensitivityRatio: Double, loop_wanted_smb: String): Double? { + val profile = profileFunction.getProfile() + val sens = profile?.getIsfMgdl("OpenAPSAutoISFPlugin") + val glucose_status = glucoseStatusProvider.glucoseStatusData + val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights) + val normalTarget = 100 + if (!dynIsfMode || sens == null || glucose_status == null) { + consoleError.add("autoISF disabled in Preferences") + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return sens + } + val high_temptarget_raises_sensitivity = exerciseMode || highTemptargetRaisesSensitivity + val meal_data = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() + var target_bg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TARGET_BG[0], HardLimits.LIMIT_TARGET_BG[1]) + var isTempTarget = false + persistenceLayer.getTemporaryTargetActiveAt(dateUtil.now())?.let { tempTarget -> + isTempTarget = true + target_bg = hardLimits.verifyHardLimits(tempTarget.target(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TEMP_TARGET_BG[0], HardLimits.LIMIT_TEMP_TARGET_BG[1]) + } + var sensitivityRatio = 1.0 + var origin_sens = "" + val low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens) + if (high_temptarget_raises_sensitivity && isTempTarget && target_bg > normalTarget + || low_temptarget_lowers_sensitivity && isTempTarget && target_bg < normalTarget + ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + val halfBasalTarget = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget) + val c = (halfBasalTarget - normalTarget).toDouble() + if (c * (c + target_bg-normalTarget) <= 0.0) { + sensitivityRatio = preferences.get(DoubleKey.AutosensMax) + } else { + sensitivityRatio = c / (c + target_bg - normalTarget) + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = min(sensitivityRatio, preferences.get(DoubleKey.AutosensMax)) + sensitivityRatio = round(sensitivityRatio, 2) + origin_sens = "from TT modifier" + consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") + } + } else { + var autosensResult = AutosensResult() + + if (constraintsChecker.isAutosensModeEnabled().value()) { + iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")?.also { + autosensResult = it.autosensResult + } + } else autosensResult.sensResult = "autosens disabled" + sensitivityRatio = autosensResult.ratio + consoleError.add("Autosens ratio: $sensitivityRatio; ") + } + // Todo include here exercise_ratio calculation + val autosensResult = AutosensResult() + + if (constraintsChecker.isAutosensModeEnabled().value()) { + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") + if (autosensData == null) { + rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) + return null + } + autosensData.autosensResult + } else autosensResult.sensResult = "autosens disabled" + + val dura05: Double = glucose_status.duraISFminutes + val avg05: Double = glucose_status.duraISFaverage + val maxISFReduction: Double = autoISF_max + var sens_modified = false + var pp_ISF = 1.0 + var delta_ISF = 1.0 + var acce_ISF = 1.0 + var acce_weight: Double = 1.0 + val bg_off = target_bg + 10.0 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 + + // calculate acce_ISF from bg acceleration and adapt ISF accordingly + val fit_corr: Double = glucose_status.corrSqu + val bg_acce: Double = glucose_status.bgAcceleration + if (glucose_status.a2 != 0.0 && fit_corr >= 0.9) { + var minmax_delta: Double = -glucose_status.a1 / 2 / glucose_status.a2 * 5 // back from 5min block to 1 min + var minmax_value: Double = round(glucose_status.a0 - minmax_delta * minmax_delta / 25 * glucose_status.a2, 1) + minmax_delta = round(minmax_delta, 1) + if (minmax_delta > 0 && bg_acce < 0) { + consoleError.add("Parabolic fit extrapolates a maximum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") + } else if (minmax_delta > 0 && bg_acce > 0.0) { + + consoleError.add("Parabolic fit extrapolates a minimum of ${convert_bg(minmax_value)} in about $minmax_delta minutes") + if (minmax_delta <= 30 && minmax_value < target_bg) { // start braking + acce_weight = -bgBrake_ISF_weight + consoleError.add("extrapolation below target soon: use bgBrake_ISF_weight of ${-acce_weight}") + } + } + } + if (fit_corr < 0.9) { + consoleError.add("acce_ISF adaptation by-passed as correlation ${round(fit_corr, 3)} is too low") + } else { + val fit_share = 10 * (fit_corr - 0.9) // 0 at correlation 0.9, 1 at 1.00 + var cap_weight = 1.0 // full contribution above target + if (acce_weight == 1.0 && glucose_status.glucose < target_bg) { // below target acce goes towards target + if (bg_acce > 0) { + if (bg_acce > 1) { + cap_weight = 0.5 + } // halve the effect below target + acce_weight = bgBrake_ISF_weight + } else if (bg_acce < 0) { + acce_weight = bgAccel_ISF_weight + } + } else if (acce_weight == 1.0) { // above target acce goes away from target + if (bg_acce < 0.0) { + acce_weight = bgBrake_ISF_weight + } else if (bg_acce > 0.0) { + acce_weight = bgAccel_ISF_weight + } + } + acce_ISF = 1.0 + bg_acce * cap_weight * acce_weight * fit_share + consoleError.add("acce_ISF adaptation is ${round(acce_ISF, 2)}") + if (acce_ISF != 1.0) { + sens_modified = true + } + } + + val bg_ISF = 1 + interpolate(100 - bg_off, "bg") + consoleError.add("bg_ISF adaptation is ${round(bg_ISF, 2)}") + var liftISF = 1.0 + var final_ISF = 1.0 + if (bg_ISF < 1.0) { + liftISF = min(bg_ISF, acce_ISF) + if (acce_ISF > 1.0) { + liftISF = bg_ISF * acce_ISF // bg_ISF could become > 1 now + consoleError.add("bg_ISF adaptation lifted to ${round(liftISF, 2)} as bg accelerates already") + } + final_ISF = withinISFlimits(liftISF, autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, isTempTarget, high_temptarget_raises_sensitivity, target_bg, normalTarget) + return min(720.0, round(sens / final_ISF, 1)) // observe ISF maximum of 720(?) + } else if (bg_ISF > 1.0) { + sens_modified = true + } + + val bg_delta = glucose_status.delta + val deltaType: String + deltaType = if (enable_pp_ISF_always || pp_ISF_hours >= (currentTime - meal_data.lastCarbTime) / 1000 / 3600) { + "pp" + } else { + "delta" + } + when { + bg_off > 0.0 -> { + consoleError.add(deltaType + "_ISF adaptation by-passed as average glucose < $target_bg+10") + } + glucose_status.shortAvgDelta < 0 -> { + consoleError.add(deltaType + "_ISF adaptation by-passed as no rise or too short lived") + } + deltaType == "pp" -> { + pp_ISF = 1.0 + max(0.0, bg_delta * pp_ISF_weight) + consoleError.add("pp_ISF adaptation is ${round(pp_ISF, 2)}") + if (pp_ISF != 1.0) { + sens_modified = true + } + + } + else -> { + delta_ISF = interpolate(bg_delta, "delta"); + // mod V14d: halve the effect below target_bg+30 + if (bg_off > -20.0) { + delta_ISF = 0.5 * delta_ISF + } + delta_ISF = 1.0 + delta_ISF + consoleError.add("delta_ISF adaptation is ${round(delta_ISF, 2)}") + + if (delta_ISF != 1.0) { + sens_modified = true + } + } + } + + var dura_ISF = 1.0 + val weightISF: Double = dura_ISF_weight + when { + meal_data.mealCOB > 0 && !enable_dura_ISF_with_COB -> { + consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB, 1)}") + } + dura05!! < 10.0 -> { + consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05"); + } + avg05!! <= target_bg -> { + consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") + } + else -> { + // fight the resistance at high levels + val dura05Weight = dura05 / 60 + val avg05Weight = weightISF / target_bg + dura_ISF += dura05Weight * avg05Weight * (avg05 - target_bg) + sens_modified = true + consoleError.add("dura_ISF adaptation is ${round(dura_ISF, 2)} because ISF ${round(sens, 1)} did not do it for ${round(dura05, 1)}m") + } + } + if (sens_modified) { + liftISF = max(dura_ISF, max(bg_ISF, max(delta_ISF, max(acce_ISF, pp_ISF)))) + if (acce_ISF < 1.0) { // 13.JAN.2022 brakes on for otherwise stronger or stable ISF + consoleError.add("strongest autoISF factor ${round(liftISF, 2)} weakened to ${round(liftISF * acce_ISF, 2)} as bg decelerates already") + liftISF = liftISF * acce_ISF // brakes on for otherwise stronger or stable ISF + } // brakes on for otherwise stronger or stable ISF + final_ISF = withinISFlimits(liftISF, autoISF_min, maxISFReduction, sensitivityRatio, origin_sens, isTempTarget, high_temptarget_raises_sensitivity, target_bg, normalTarget) + return round(sens / final_ISF, 1) + } + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return sens // nothing changed + } + + fun interpolate(xdata: Double, type: String): Double { // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... + val polyX: Array + val polyY: Array + if (type == "bg") { + // ... <---------------------- glucose ----------------------> + polyX = arrayOf(50.0, 60.0, 80.0, 90.0, 100.0, 110.0, 150.0, 180.0, 200.0) + polyY = arrayOf(-0.5, -0.5, -0.3, -0.2, 0.0, 0.0, 0.5, 0.7, 0.7) + } else { + // ... <------- delta --------> + polyX = arrayOf(2.0, 7.0, 12.0, 16.0, 20.0) + polyY = arrayOf(0.0, 0.0, 0.4, 0.7, 0.7) + } + val polymax: Int = polyX.size - 1 + var step = polyX[0] + var sVal = polyY[0] + var stepT = polyX[polymax] + var sValold = polyY[polymax] + + var newVal = 1.0 + var lowVal = 1.0 + val topVal: Double + val lowX: Double + val topX: Double + val myX: Double + var lowLabl = step + + if (step > xdata) { + // extrapolate backwards + stepT = polyX[1] + sValold = polyY[1] + lowVal = sVal + topVal = sValold + lowX = step + topX = stepT + myX = xdata + newVal = lowVal + (topVal - lowVal) / (topX - lowX) * (myX - lowX) + } else if (stepT < xdata) { + // extrapolate forwards + step = polyX[polymax - 1] + sVal = polyY[polymax - 1] + lowVal = sVal + topVal = sValold + lowX = step + topX = stepT + myX = xdata + newVal = lowVal + (topVal - lowVal) / (topX - lowX) * (myX - lowX) + } else { + // interpolate + for (i: Int in 0..polymax) { + step = polyX[i] + sVal = polyY[i] + if (step == xdata) { + newVal = sVal + break + } else if (step > xdata) { + topVal = sVal + lowX = lowLabl + myX = xdata + topX = step + newVal = lowVal + (topVal - lowVal) / (topX - lowX) * (myX - lowX) + break + } + lowVal = sVal + lowLabl = step + } + } + newVal = if (type == "delta") { + newVal * delta_ISFrange_weight + } // delta range + else if (xdata > 100) { + newVal * higher_ISFrange_weight + } // higher BG range + else { + newVal * lower_ISFrange_weight + } // lower BG range + return newVal + } + + fun withinISFlimits( + liftISF: Double, minISFReduction: Double, maxISFReduction: Double, sensitivityRatio: Double, origin_sens: String, temptargetSet: Boolean, + high_temptarget_raises_sensitivity: Boolean, target_bg: Double, normalTarget: Int + ): Double { + var liftISFlimited: Double = liftISF + if (liftISF < minISFReduction) { + consoleError.add("weakest autoISF factor ${round(liftISF, 2)} limited by autoISF_min $minISFReduction") + liftISFlimited = minISFReduction + } else if (liftISF > maxISFReduction) { + consoleError.add("strongest autoISF factor ${round(liftISF, 2)} limited by autoISF_max $maxISFReduction") + liftISFlimited = maxISFReduction + } + val finalISF: Double + var origin_sens_final = origin_sens + if (high_temptarget_raises_sensitivity && temptargetSet && target_bg > normalTarget) { + finalISF = liftISFlimited * sensitivityRatio + origin_sens_final = " including exercise mode impact" + } else if (liftISFlimited >= 1) { + finalISF = max(liftISFlimited, sensitivityRatio) + } else { + finalISF = min(liftISFlimited, sensitivityRatio) + } + consoleError.add("final ISF factor is ${round(finalISF, 2)}" + origin_sens_final) + consoleError.add("----------------------------------") + consoleError.add("end autoISF") + consoleError.add("----------------------------------") + return finalISF + } + + fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double): String { + if (!microBolusAllowed) { + return "AAPS" // see message in enable_smb + } + if (profile.temptargetSet && enableSMB_EvenOn_OddOff || profile.min_bg == profile.max_bg && enableSMB_EvenOn_OddOff_always && !profile.temptargetSet) { + val target = convert_bg(profile.target_bg) + val msgType: String + val evenTarget: Boolean + val msgUnits: String + val msgTail: String + val msgEven: String + val msg: String + msgType = if (profile.temptargetSet) { + "TempTarget" + } else { + "profile target" + } + if (profile.out_units == "mmol/L") { + evenTarget = (target.toDouble() * 10.0).toInt() % 2 == 0 + msgUnits = "has " + msgTail = "decimal" + } else { + evenTarget = target.toInt() % 2 == 0 + msgUnits = "is " + msgTail = "number" + } + msgEven = if (evenTarget) { + "even " + } else { + "odd " + } + val iobTHeffective = iobThresholdPercent + if (!evenTarget) { + consoleError.add("SMB disabled; $msgType $target $msgUnits $msgEven $msgTail") + consoleError.add("Loop at minimum power") + return "blocked" + } else if (profile.max_iob == 0.0) { + consoleError.add("SMB disabled because of max_iob=0") + return "blocked" + } else if (iobTHeffective / 100.0 < iob_data_iob / (profile.max_iob * iobTH_reduction_ratio)) { + if (iobTH_reduction_ratio != 1.0) { + consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob * iobTH_reduction_ratio, 2)} due to profile % and/or exercise mode") + msg = "effective maxIOB ${round(profile.max_iob * iobTH_reduction_ratio, 2)}" + } else { + msg = "maxIOB ${profile.max_iob}" + } + consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is more than $iobTHeffective% of $msg") + consoleError.add("Full Loop capped"); + return "iobTH"; + } else { + consoleError.add("SMB enabled; $msgType $target $msgUnits $msgEven $msgTail") + if (profile.target_bg < 100) { // indirect assessment; later set it in GUI + consoleError.add("Loop at full power") + return "fullLoop" // even number + } else { + consoleError.add("Loop at medium power") + return "enforced" // even number + } + } + } + consoleError.add("Full Loop disabled") + return "AAPS" // leave it to standard AAPS + } + + fun determine_varSMBratio(profile: OapsProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target + var smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range + if (smb_delivery_ratio_bg_range < 10) { + smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 + } // was in mmol/l + var fix_SMB: Double = smb_delivery_ratio + var lower_SMB = min(smb_delivery_ratio_min, smb_delivery_ratio_max) + var higher_SMB = max(smb_delivery_ratio_min, smb_delivery_ratio_max) + var higher_bg = target_bg + smb_delivery_ratio_bg_range + var new_SMB: Double = fix_SMB + if (smb_delivery_ratio_bg_range > 0) { + new_SMB = lower_SMB + (higher_SMB - lower_SMB) * (bg - target_bg) / smb_delivery_ratio_bg_range + new_SMB = max(lower_SMB, min(higher_SMB, new_SMB)) // cap if outside target_bg--higher_bg + } + if (loop_wanted_smb == "fullLoop") { // go for max impactError.add("SMB delivery ratio set to ${max(fix_SMB, new_SMB)} as max of fixed and interpolated values") + return max(fix_SMB, new_SMB) + } + + if (smb_delivery_ratio_bg_range == 0.0) { // deactivated in SMB extended menu + consoleError.add("SMB delivery ratio set to fixed value $fix_SMB") + return fix_SMB + } + if (bg <= target_bg) { + consoleError.add("SMB delivery ratio limited by minimum value $lower_SMB") + return lower_SMB + } + if (bg >= higher_bg) { + consoleError.add("SMB delivery ratio limited by maximum value $higher_SMB") + return higher_SMB + } + consoleError.add("SMB delivery ratio set to interpolated value $new_SMB") + return new_SMB + } + + override fun addPreferenceScreen(preferenceManager: PreferenceManager, parent: PreferenceScreen, context: Context, requiredKey: String?) { + if (requiredKey != null && requiredKey != "absorption_smb_advanced") return + val category = PreferenceCategory(context) + parent.addPreference(category) + category.apply { + key = "openapsautoisf_settings" + title = rh.gs(R.string.openaps_auto_isf) + initialExpandedChildrenCount = 0 + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsMaxBasal, dialogMessage = R.string.openapsma_max_basal_summary, title = R.string.openapsma_max_basal_title)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsSmbMaxIob, dialogMessage = R.string.openapssmb_max_iob_summary, title = R.string.openapssmb_max_iob_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsfWeights, summary = R.string.autoISF_settings_summary, title = R.string.autoISF_settings_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutosens, title = R.string.openapsama_use_autosens)) + //addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsDynIsfAdjustmentFactor, dialogMessage = R.string.dyn_isf_adjust_summary, title = R.string.dyn_isf_adjust_title)) + addPreference(AdaptiveUnitPreference(ctx = context, unitKey = UnitDoubleKey.ApsLgsThreshold, dialogMessage = R.string.lgs_threshold_summary, title = R.string.lgs_threshold_title)) + //addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsDynIsfAdjustSensitivity, summary = R.string.dynisf_adjust_sensitivity_summary, title = R.string.dynisf_adjust_sensitivity)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsSensitivityRaisesTarget, summary = R.string.sensitivity_raises_target_summary, title = R.string.sensitivity_raises_target_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsResistanceLowersTarget, summary = R.string.resistance_lowers_target_summary, title = R.string.resistance_lowers_target_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmb, summary = R.string.enable_smb_summary, title = R.string.enable_smb)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbWithHighTt, summary = R.string.enable_smb_with_high_temp_target_summary, title = R.string.enable_smb_with_high_temp_target)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbAlways, summary = R.string.enable_smb_always_summary, title = R.string.enable_smb_always)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbWithCob, summary = R.string.enable_smb_with_cob_summary, title = R.string.enable_smb_with_cob)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbWithLowTt, summary = R.string.enable_smb_with_temp_target_summary, title = R.string.enable_smb_with_temp_target)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbAfterCarbs, summary = R.string.enable_smb_after_carbs_summary, title = R.string.enable_smb_after_carbs)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseUam, summary = R.string.enable_uam_summary, title = R.string.enable_uam)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsMaxSmbFrequency, title = R.string.smb_interval_summary)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsMaxMinutesOfBasalToLimitSmb, title = R.string.smb_max_minutes_summary)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsUamMaxMinutesOfBasalToLimitSmb, dialogMessage = R.string.uam_smb_max_minutes, title = R.string.uam_smb_max_minutes_summary)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsCarbsRequestThreshold, dialogMessage = R.string.carbs_req_threshold_summary, title = R.string.carbs_req_threshold)) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "absorption_smb_advanced" + title = rh.gs(app.aaps.core.ui.R.string.advanced_settings_title) + addPreference( + AdaptiveIntentPreference( + ctx = context, + intentKey = IntentKey.ApsLinkToDocs, + intent = Intent().apply { action = Intent.ACTION_VIEW; data = Uri.parse(rh.gs(R.string.openapsama_link_to_preference_json_doc)) }, + summary = R.string.openapsama_link_to_preference_json_doc_txt + ) + ) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAlwaysUseShortDeltas, summary = R.string.always_use_short_avg_summary, title = R.string.always_use_short_avg)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsMaxDailyMultiplier, dialogMessage = R.string.openapsama_max_daily_safety_multiplier_summary, title = R.string.openapsama_max_daily_safety_multiplier)) + addPreference( + AdaptiveDoublePreference( + ctx = context, + doubleKey = DoubleKey.ApsMaxCurrentBasalMultiplier, + dialogMessage = R.string.openapsama_current_basal_safety_multiplier_summary, + title = R.string.openapsama_current_basal_safety_multiplier + ) + ) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "auto_isf_settings" + title = rh.gs(R.string.autoISF_settings_title) + summary = rh.gs(R.string.autoISF_settings_summary) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsfWeights, summary = R.string.openapsama_enable_autoISF, title = R.string.openapsama_enable_autoISF)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfMin, dialogMessage = R.string.openapsama_autoISF_min_summary, title = R.string.openapsama_autoISF_min)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfMax, dialogMessage = R.string.openapsama_autoISF_max_summary, title = R.string.openapsama_autoISF_max)) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "acce_ISF_settings" + title = rh.gs(R.string.acce_ISF_settings_title) + summary = rh.gs(R.string.acce_ISF_settings_summary) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfBgAccelWeight, dialogMessage = R.string.openapsama_bgAccel_ISF_weight_summary, title = R.string.openapsama_bgAccel_ISF_weight)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfBgBrakeWeight, dialogMessage = R.string.openapsama_bgBrake_ISF_weight_summary, title = R.string.openapsama_bgBrake_ISF_weight)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "bg_ISF_settings" + title = rh.gs(R.string.bg_ISF_settings_title) + summary = rh.gs(R.string.bg_ISF_settings_summary) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfLowBgWeight, dialogMessage = R.string.openapsama_lower_ISFrange_weight_summary, title = R.string.openapsama_lower_ISFrange_weight)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfHighBgWeight, dialogMessage = R.string.openapsama_higher_ISFrange_weight_summary, title = R.string.openapsama_higher_ISFrange_weight)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "pp_ISF_settings" + title = rh.gs(R.string.pp_ISF_settings_title) + summary = rh.gs(R.string.pp_ISF_settings_summary) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfPpAlways, summary = R.string.enable_postprandial_ISF_always_summary, title = R.string.enable_postprandial_ISF_always)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsAutoIsfPpIsfHours, dialogMessage = R.string.openapsama_pp_ISF_hours_summary, title = R.string.openapsama_pp_ISF_hours)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfPpWeight, dialogMessage = R.string.openapsama_pp_ISF_weight_summary, title = R.string.openapsama_pp_ISF_weight)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "delta_ISF_settings" + title = rh.gs(R.string.delta_ISF_settings_title) + summary = rh.gs(R.string.delta_ISF_settings_summary) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfDeltaWeight, dialogMessage = R.string.openapsama_delta_ISFrange_weight_summary, title = R.string.openapsama_delta_ISFrange_weight)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "dura_ISF_settings" + title = rh.gs(R.string.dura_ISF_settings_title) + summary = rh.gs(R.string.dura_ISF_settings_summary) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfDuraAfterCarbs, summary = R.string.enableautoISFwithcob_summary, title = R.string.enableautoISFwithcob)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfDuraWeight, dialogMessage = R.string.openapsama_dura_ISF_weight_summary, title = R.string.openapsama_dura_ISF_weight)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "smb_delivery_settings" + title = rh.gs(R.string.smb_delivery_settings_title) + summary = rh.gs(R.string.smb_delivery_settings_summary) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfSmbDeliveryRatio, dialogMessage = R.string.openapsama_smb_delivery_ratio_summary, title = R.string.openapsama_smb_delivery_ratio)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfSmbDeliveryRatioMin, dialogMessage = R.string.openapsama_smb_delivery_ratio_min_summary, title = R.string.openapsama_smb_delivery_ratio_min)) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfSmbDeliveryRatioMax, dialogMessage = R.string.openapsama_smb_delivery_ratio_max_summary, title = R.string.openapsama_smb_delivery_ratio_max)) + addPreference( + AdaptiveUnitPreference( + ctx = context, + unitKey = UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange, + dialogMessage = R.string.openapsama_smb_delivery_ratio_bg_range_summary, + title = R.string.openapsama_smb_delivery_ratio_bg_range + ) + ) + addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfSmbMaxRangeExtension, dialogMessage = R.string.openapsama_smb_max_range_extension_summary, title = R.string.openapsama_smb_max_range_extension)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfSmbOnEvenTt, summary = R.string.enableSMB_EvenOn_OddOff_summary, title = R.string.enableSMB_EvenOn_OddOff)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfSmbOnEvenPt, summary = R.string.enableSMB_EvenOn_OddOff_always_summary, title = R.string.enableSMB_EvenOn_OddOff_always)) + }) + addPreference(preferenceManager.createPreferenceScreen(context).apply { + key = "full_loop_settings" + title = rh.gs(R.string.full_loop_settings_title) + summary = rh.gs(R.string.full_loop_settings_summary) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsAutoIsfIobThPercent, dialogMessage = R.string.openapsama_iob_threshold_percent_summary, title = R.string.openapsama_iob_threshold_percent)) + }) + }) + } + } } \ No newline at end of file diff --git a/plugins/aps/src/main/res/values/strings.xml b/plugins/aps/src/main/res/values/strings.xml index 564b2484432..3753a87fef0 100644 --- a/plugins/aps/src/main/res/values/strings.xml +++ b/plugins/aps/src/main/res/values/strings.xml @@ -202,6 +202,8 @@ dura_ISF settings: ISF for blood glucose plateau above target smb delivery settings smb delivery settings: Set of options to increase the actual SMB size which can be delivered in situations where ISF was strengthened, i.e. fairly low ISF figure.\n\nUSE WITH CAUTION + Full Loop Settings + Full Loop Settings: Adjust iobTH and total acce weights for meal types Enable ISF adaptation by glucose behaviour Default value: 1.2\nThis is a multiplier cap for autoISF to set a limit on how high the autoISF ratio can be, which in turn determines how low it can adjust ISF.\n\nWARNING: Be extremely careful when using values above 2.5 Default value: 1.0\nThis 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. diff --git a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml b/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml deleted file mode 100644 index a5f39854ba1..00000000000 --- a/plugins/aps/src/main/res/xml/pref_openapsautoisf.xml +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9f3ae4e0600c0bc4dd1e2cbf476f107952be609f Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 2 Mar 2024 11:56:39 +0100 Subject: [PATCH 12/38] Fix Build --- .../aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index ed646675503..a8bca052c50 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -17,8 +17,6 @@ import app.aaps.core.interfaces.aps.APS import app.aaps.core.interfaces.aps.APSResult import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp -import app.aaps.core.interfaces.aps.GlucoseStatus -import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck import app.aaps.core.interfaces.configuration.Config @@ -48,7 +46,6 @@ import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.HardLimits import app.aaps.core.interfaces.utils.Round import app.aaps.core.keys.AdaptiveIntentPreference -import app.aaps.core.keys.AdaptiveSwitchPreference import app.aaps.core.keys.BooleanKey import app.aaps.core.keys.DoubleKey import app.aaps.core.keys.IntKey @@ -67,12 +64,12 @@ import app.aaps.core.objects.profile.ProfileSealed import app.aaps.core.utils.MidnightUtils import app.aaps.core.validators.AdaptiveDoublePreference import app.aaps.core.validators.AdaptiveIntPreference +import app.aaps.core.validators.AdaptiveSwitchPreference import app.aaps.core.validators.AdaptiveUnitPreference import app.aaps.plugins.aps.OpenAPSFragment import app.aaps.plugins.aps.R import app.aaps.plugins.aps.events.EventOpenAPSUpdateGui import app.aaps.plugins.aps.events.EventResetOpenAPSGui -import app.aaps.plugins.aps.openAPS.TddStatus import dagger.android.HasAndroidInjector import org.json.JSONObject import javax.inject.Inject From 1897694cca634f1721f8c2b6f189f9e32a7974a5 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Sat, 2 Mar 2024 16:40:16 +0100 Subject: [PATCH 13/38] fix randomBG scaling for 1 minute CGM interval --- .../src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt b/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt index 7c63b2046d2..e9c5b418ea6 100644 --- a/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt +++ b/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt @@ -121,7 +121,7 @@ class RandomBgPlugin @Inject constructor( val cal = GregorianCalendar() val currentMinute = cal[Calendar.MINUTE] + (cal[Calendar.HOUR_OF_DAY] % 2) * 60 - val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (SecureRandom().nextDouble() - 0.5) * (max - min) * 0.4 + val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (SecureRandom().nextDouble() - 0.5) * (max - min) * 0.08 * interval.toDouble() cal[Calendar.MILLISECOND] = 0 cal[Calendar.SECOND] = 0 From a26c5efd20cf338c0c5d9c4870336b06b0374042 Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 2 Mar 2024 17:29:07 +0100 Subject: [PATCH 14/38] Fix AutoISF menu in preferences --- .../aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index a8bca052c50..ef2a74af2ce 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -898,7 +898,17 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } override fun addPreferenceScreen(preferenceManager: PreferenceManager, parent: PreferenceScreen, context: Context, requiredKey: String?) { - if (requiredKey != null && requiredKey != "absorption_smb_advanced") return + if (requiredKey != null && + requiredKey != "absorption_smb_advanced" && + requiredKey != "auto_isf_settings" && + requiredKey != "acce_ISF_settings" && + requiredKey != "bg_ISF_settings" && + requiredKey != "pp_ISF_settings" && + requiredKey != "delta_ISF_settings" && + requiredKey != "dura_ISF_settings" && + requiredKey != "smb_delivery_settings" && + requiredKey != "full_loop_settings" + ) return val category = PreferenceCategory(context) parent.addPreference(category) category.apply { From 2411a1ed04e80a1784fa429a6d2af2f8ec7dac02 Mon Sep 17 00:00:00 2001 From: Philoul Date: Sun, 3 Mar 2024 00:14:26 +0100 Subject: [PATCH 15/38] Fix AutoISF Crash --- .../converters/APSResultExtension.kt | 6 +++-- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 4 ++-- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 23 +++++++------------ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt b/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt index dc7e448d92b..fa808549e38 100644 --- a/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt +++ b/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt @@ -17,7 +17,8 @@ import kotlinx.serialization.json.Json fun app.aaps.database.entities.APSResult.fromDb(injector: HasAndroidInjector): APSResult = when (algorithm) { app.aaps.database.entities.APSResult.Algorithm.AMA, - app.aaps.database.entities.APSResult.Algorithm.SMB -> + app.aaps.database.entities.APSResult.Algorithm.SMB, + app.aaps.database.entities.APSResult.Algorithm.AUTO_ISF -> DetermineBasalResult(injector, Json.decodeFromString(this.resultJson)).also { result -> result.date = this.timestamp result.glucoseStatus = this.glucoseStatusJson?.let { Json.decodeFromString(it) } @@ -35,7 +36,8 @@ fun app.aaps.database.entities.APSResult.fromDb(injector: HasAndroidInjector): A fun APSResult.toDb(): app.aaps.database.entities.APSResult = when (algorithm) { APSResult.Algorithm.AMA, - APSResult.Algorithm.SMB -> + APSResult.Algorithm.SMB, + APSResult.Algorithm.AUTO_ISF -> app.aaps.database.entities.APSResult( timestamp = this.date, algorithm = this.algorithm.toDb(), diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index b70fe5fc43b..4cebdf738fa 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -155,7 +155,7 @@ class DetermineBasalAutoISF @Inject constructor( consoleError.clear() consoleLog.clear() var rT = RT( - algorithm = APSResult.Algorithm.SMB, + algorithm = APSResult.Algorithm.AUTO_ISF, runningDynamicIsf = dynIsfMode, timestamp = currentTime, consoleLog = consoleLog, @@ -381,7 +381,7 @@ class DetermineBasalAutoISF @Inject constructor( //console.error(reservoir_data); rT = RT( - algorithm = APSResult.Algorithm.SMB, + algorithm = APSResult.Algorithm.AUTO_ISF, runningDynamicIsf = dynIsfMode, timestamp = currentTime, bg = bg, diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index ef2a74af2ce..6b06748ea45 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -29,7 +29,6 @@ import app.aaps.core.interfaces.iob.GlucoseStatusProvider import app.aaps.core.interfaces.iob.IobCobCalculator import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag -import app.aaps.core.interfaces.notifications.Notification import app.aaps.core.interfaces.plugin.ActivePlugin import app.aaps.core.interfaces.plugin.PluginBase import app.aaps.core.interfaces.plugin.PluginDescription @@ -40,7 +39,6 @@ import app.aaps.core.interfaces.profiling.Profiler import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.events.EventAPSCalculationFinished -import app.aaps.core.interfaces.stats.TddCalculator import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.HardLimits @@ -98,7 +96,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val processedTbrEbData: ProcessedTbrEbData, private val persistenceLayer: PersistenceLayer, private val glucoseStatusProvider: GlucoseStatusProvider, - private val tddCalculator: TddCalculator, private val bgQualityCheck: BgQualityCheck, private val uiInteraction: UiInteraction, private val determineBasalAutoISF: DetermineBasalAutoISF, @@ -119,7 +116,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // last values override var lastAPSRun: Long = 0 - override val algorithm = APSResult.Algorithm.SMB + override val algorithm = APSResult.Algorithm.AUTO_ISF override var lastAPSResult: DetermineBasalResult? = null private var consoleError = mutableListOf() @@ -145,18 +142,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) private val exerciseMode = SMBDefaults.exercise_mode private val highTemptargetRaisesSensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) - override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) + private var enableDynAps = true + override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) && enableDynAps override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() val sensitivity = calculateVariableIsf(start, bg = null) - if (sensitivity.second == null) - uiInteraction.addNotificationValidTo( - Notification.DYN_ISF_FALLBACK, start, - rh.gs(R.string.fallback_to_isf_no_tdd), Notification.INFO, dateUtil.now() + T.mins(1).msecs() - ) - else - uiInteraction.dismissNotification(Notification.DYN_ISF_FALLBACK) profiler.log(LTag.APS, String.format("getIsfMgdl() %s %f %s %s", sensitivity.first, sensitivity.second, dateUtil.dateAndTimeAndSecondsString(start), caller), start) return sensitivity.second?.let { it * multiplier } } @@ -212,8 +203,10 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return Pair("HIT", cached) } // no cached result found, let's calculate the value - + enableDynAps = false // disable supportsDynamicIsf feature to get profile ISF value val sensitivity = (autoISF(timestamp) ?: 1.0) * profile.getIsfMgdlTimeFromMidnight(MidnightUtils.secondsFromMidnight(timestamp)) + aapsLogger.debug("XXXXX $sensitivity ${profile.getIsfMgdlTimeFromMidnight(MidnightUtils.secondsFromMidnight(timestamp))}") + enableDynAps = true // enable supportsDynamicIsf feature after calculation dynIsfCache.put(key, sensitivity) if (dynIsfCache.size() > 1000) dynIsfCache.clear() return Pair("CALC", sensitivity) @@ -662,10 +655,10 @@ open class OpenAPSAutoISFPlugin @Inject constructor( meal_data.mealCOB > 0 && !enable_dura_ISF_with_COB -> { consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB, 1)}") } - dura05!! < 10.0 -> { + dura05 < 10.0 -> { consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05"); } - avg05!! <= target_bg -> { + avg05 <= target_bg -> { consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") } else -> { From c9ee1e51ceddbdc241c43c6fd5d72a9964bf5d62 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Thu, 7 Mar 2024 15:35:52 +0100 Subject: [PATCH 16/38] show relevant parabola fit results --- .../aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt index f7fe7035844..d2da2bf2ccc 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt @@ -131,7 +131,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider { openAPSPlugin.lastAPSResult?.let { lastAPSResult -> binding.result.text = lastAPSResult.rawData().dataClassToHtml() binding.request.text = lastAPSResult.resultAsSpanned() - binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta")) + binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta", "corrSqu", "bgAcceleration")) binding.currenttemp.text = lastAPSResult.currentTemp?.dataClassToHtml() binding.iobdata.text = rh.gs(R.string.array_of_elements, lastAPSResult.iobData?.size) + "\n" + lastAPSResult.iob?.dataClassToHtml() binding.profile.text = lastAPSResult.oapsProfile?.dataClassToHtml() From 2c38274b8988a169ce71c3adf86b166264379a73 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Thu, 7 Mar 2024 15:36:50 +0100 Subject: [PATCH 17/38] enablers for exercise mode --- .../plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 6b06748ea45..597332f00cc 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -73,7 +73,6 @@ import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton import kotlin.math.floor -import kotlin.math.ln import kotlin.math.max import kotlin.math.min import kotlin.math.pow @@ -284,7 +283,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } autosensResult = autosensData.autosensResult } else autosensResult.sensResult = "autosens disabled" - val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget) + val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), isTempTarget) val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() val iobData = iobArray[0] val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 @@ -509,6 +508,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val c = (halfBasalTarget - normalTarget).toDouble() if (c * (c + target_bg-normalTarget) <= 0.0) { sensitivityRatio = preferences.get(DoubleKey.AutosensMax) + consoleError.add("Sensitivity decrease for temp target of $target_bg limited by Autosens_max; ") + } else { sensitivityRatio = c / (c + target_bg - normalTarget) // limit sensitivityRatio to profile.autosens_max (1.2x by default) @@ -917,6 +918,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( //addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsDynIsfAdjustSensitivity, summary = R.string.dynisf_adjust_sensitivity_summary, title = R.string.dynisf_adjust_sensitivity)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsSensitivityRaisesTarget, summary = R.string.sensitivity_raises_target_summary, title = R.string.sensitivity_raises_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsResistanceLowersTarget, summary = R.string.resistance_lowers_target_summary, title = R.string.resistance_lowers_target_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfHighTtRaisesSens, summary = R.string.high_temptarget_raises_sensitivity_summary, title = R.string.high_temptarget_raises_sensitivity_title)) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfLowTtLowersSens, summary = R.string.low_temptarget_lowers_sensitivity_summary, title = R.string.low_temptarget_lowers_sensitivity_title)) + addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsAutoIsfHalfBasalExerciseTarget, summary = R.string.half_basal_exercise_target_summary, title = R.string.half_basal_exercise_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmb, summary = R.string.enable_smb_summary, title = R.string.enable_smb)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbWithHighTt, summary = R.string.enable_smb_with_high_temp_target_summary, title = R.string.enable_smb_with_high_temp_target)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseSmbAlways, summary = R.string.enable_smb_always_summary, title = R.string.enable_smb_always)) From ef7f0933f1dcb276744372798ffd2f4bb4633467 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Thu, 7 Mar 2024 15:38:38 +0100 Subject: [PATCH 18/38] prepare kt_test for new AutoISF plugin --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 75 ++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 4fb42475efa..8cab162a7e1 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -17,6 +17,10 @@ import app.aaps.core.interfaces.maintenance.FileListProvider import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.storage.Storage import app.aaps.core.interfaces.utils.DateUtil +import app.aaps.core.keys.DoubleKey +import app.aaps.core.keys.BooleanKey +import app.aaps.core.keys.IntKey +import app.aaps.core.keys.Preferences import app.aaps.core.utils.JsonHelper import app.aaps.di.TestApplication import app.aaps.plugins.aps.openAPSAMA.DetermineBasalAMA @@ -55,6 +59,7 @@ class ReplayApsResultsTest @Inject constructor() { @Inject lateinit var determineBasalAutoISF: DetermineBasalAutoISF @Inject lateinit var sp: SP @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var preferences: Preferences private val context = ApplicationProvider.getApplicationContext() @@ -93,11 +98,11 @@ class ReplayApsResultsTest @Inject constructor() { OpenAPSAMAPlugin::class.simpleName -> amas++ } when (algorithm) { - OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) + //OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) "OpenAPSSMBAutoISFPlugin" -> testOpenAPSSMBAutoISF(filename, input, output, injector) - "OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) - OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) - else -> error("Unsupported") + //"OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) + //OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) + //else -> error("Unsupported") } } aapsLogger.info(LTag.CORE, "\n**********\nAMA: $amas\nSMB: $smbs\nDynISFs: $dynisfs\nAutoISFs: $autoisfs\nJS time: $jsTime\nKT time: $ktTime\n**********") @@ -662,6 +667,51 @@ class ReplayApsResultsTest @Inject constructor() { for (i in 0 until determineBasalResult.iobData!!.length()) iobData.add(determineBasalResult.iobData!!.getJSONObject(i).toIob()) val currentTime = determineBasalResult.currentTime + val oprofile = OapsProfile( + dia = 0.0, + min_5m_carbimpact = 0.0, + max_iob = determineBasalResult.profile.getDouble("max_iob"), + max_daily_basal = determineBasalResult.profile.getDouble("max_daily_basal"), + max_basal = determineBasalResult.profile.getDouble("max_basal"), + min_bg = determineBasalResult.profile.getDouble("min_bg"), + max_bg = determineBasalResult.profile.getDouble("max_bg"), + target_bg = determineBasalResult.profile.getDouble("target_bg"), + carb_ratio = determineBasalResult.profile.getDouble("carb_ratio"), + sens = determineBasalResult.profile.getDouble("sens"), + autosens_adjust_targets = false, + max_daily_safety_multiplier = determineBasalResult.profile.getDouble("max_daily_safety_multiplier"), + current_basal_safety_multiplier = determineBasalResult.profile.getDouble("current_basal_safety_multiplier"), + lgsThreshold = null, + high_temptarget_raises_sensitivity = determineBasalResult.profile.getBoolean("high_temptarget_raises_sensitivity"), + low_temptarget_lowers_sensitivity = determineBasalResult.profile.getBoolean("low_temptarget_lowers_sensitivity"), + sensitivity_raises_target = determineBasalResult.profile.getBoolean("sensitivity_raises_target"), + resistance_lowers_target = determineBasalResult.profile.getBoolean("resistance_lowers_target"), + adv_target_adjustments = determineBasalResult.profile.getBoolean("adv_target_adjustments"), + exercise_mode = determineBasalResult.profile.getBoolean("exercise_mode"), + half_basal_exercise_target = determineBasalResult.profile.getInt("half_basal_exercise_target"), + maxCOB = determineBasalResult.profile.getInt("maxCOB"), + skip_neutral_temps = determineBasalResult.profile.getBoolean("skip_neutral_temps"), + remainingCarbsCap = determineBasalResult.profile.getInt("remainingCarbsCap"), + enableUAM = determineBasalResult.profile.getBoolean("enableUAM"), + A52_risk_enable = determineBasalResult.profile.getBoolean("A52_risk_enable"), + SMBInterval = determineBasalResult.profile.getInt("SMBInterval"), + enableSMB_with_COB = determineBasalResult.profile.getBoolean("enableSMB_with_COB"), + enableSMB_with_temptarget = determineBasalResult.profile.getBoolean("enableSMB_with_temptarget"), + allowSMB_with_high_temptarget = determineBasalResult.profile.getBoolean("allowSMB_with_high_temptarget"), + enableSMB_always = determineBasalResult.profile.getBoolean("enableSMB_always"), + enableSMB_after_carbs = determineBasalResult.profile.getBoolean("enableSMB_after_carbs"), + maxSMBBasalMinutes = determineBasalResult.profile.getInt("maxSMBBasalMinutes"), + maxUAMSMBBasalMinutes = determineBasalResult.profile.getInt("maxUAMSMBBasalMinutes"), + bolus_increment = determineBasalResult.profile.getDouble("bolus_increment"), + carbsReqThreshold = determineBasalResult.profile.getInt("carbsReqThreshold"), + current_basal = determineBasalResult.profile.getDouble("current_basal"), + temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), + autosens_max = determineBasalResult.profile.getDouble("autosens_max"), + out_units = determineBasalResult.profile.optString("out_units"), + variable_sens = 0.0, + insulinDivisor = 0, + TDD = 0.0 + ) val profile = AutoISFProfile( dia = 0.0, min_5m_carbimpact = 0.0, @@ -739,13 +789,19 @@ class ReplayApsResultsTest @Inject constructor() { glucose_status = glucoseStatus, currenttemp = currentTemp, iob_data_array = iobData.toTypedArray(), - profile = profile, + profile = oprofile, autosens_data = autosensData, meal_data = meatData, microBolusAllowed = determineBasalResult.microBolusAllowed, currentTime = currentTime, flatBGsDetected = determineBasalResult.flatBGsDetected, - dynIsfMode = false + dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights), + iob_threshold_percent = preferences.get(IntKey.ApsAutoIsfIobThPercent), + smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension), + profile_percentage = 100, + smb_ratio = 0.5, + loop_wanted_smb = "dummy", + auto_isf_console = mutableListOf("start AutoISF", "end AutoISF") ) val endKt = System.currentTimeMillis() ktTime += (endKt - startKt) @@ -757,17 +813,18 @@ class ReplayApsResultsTest @Inject constructor() { aapsLogger.debug(LTag.APS, "File: $filename") // // assertThat(resultKt.reason.toString()).isEqualTo(result?.json?.getString("reason")) assertThat(resultKt.tick ?: "").isEqualTo(result?.json()?.optString("tick")) - assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) +// assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("targetBG")) assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result?.json()?.optDouble("insulinReq")) - assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) - assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) +// assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) +// assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) assertThat(resultKt.units ?: Double.NaN).isEqualTo(result?.json()?.optDouble("units")) assertThat(resultKt.sensitivityRatio ?: Double.NaN).isEqualTo(result?.json()?.optDouble("sensitivityRatio")) assertThat(resultKt.duration ?: 0).isEqualTo(result?.json()?.optInt("duration")) assertThat(resultKt.rate ?: Double.NaN).isEqualTo(result?.json()?.optDouble("rate")) assertThat(resultKt.COB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("COB")) assertThat(resultKt.IOB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("IOB")) + assertThat(resultKt.variable_sens ?: Double.NaN).isEqualTo(result?.json()?.optDouble("variable_sens")) } enum class TestSource { ASSET, FILE } From 5dc33f135ce11b37343fe6a26b9e2854dab275f0 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Thu, 7 Mar 2024 15:40:19 +0100 Subject: [PATCH 19/38] Revert "fix randomBG scaling for 1 minute CGM interval" This reverts commit 1897694cca634f1721f8c2b6f189f9e32a7974a5. --- .../src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt b/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt index e9c5b418ea6..7c63b2046d2 100644 --- a/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt +++ b/plugins/source/src/main/kotlin/app/aaps/plugins/source/RandomBgPlugin.kt @@ -121,7 +121,7 @@ class RandomBgPlugin @Inject constructor( val cal = GregorianCalendar() val currentMinute = cal[Calendar.MINUTE] + (cal[Calendar.HOUR_OF_DAY] % 2) * 60 - val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (SecureRandom().nextDouble() - 0.5) * (max - min) * 0.08 * interval.toDouble() + val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2 + (SecureRandom().nextDouble() - 0.5) * (max - min) * 0.4 cal[Calendar.MILLISECOND] = 0 cal[Calendar.SECOND] = 0 From 1dfbef9375bd41ebbc4c34e3b9e289590fc5960d Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Sat, 9 Mar 2024 16:32:27 +0100 Subject: [PATCH 20/38] fix int division for effective iobTH --- .../aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 4cebdf738fa..82aeee412ec 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -1043,8 +1043,8 @@ class DetermineBasalAutoISF @Inject constructor( if (dynIsfMode) { microBolus = Math.min(insulinReq * smb_ratio, maxBolus) // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun - val iobTHtolerance = 130 - val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000 * profile.max_iob * iobTH_reduction_ratio + val iobTHtolerance = 130.0 + val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000.0 * profile.max_iob * iobTH_reduction_ratio if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb == "fullLoop" || loop_wanted_smb == "enforced")) { microBolus = iobTHvirtual - iob_data.iob consoleError.add("Full loop capped SMB at ${round(microBolus, 2)} to not exceed $iobTHtolerance% of effective iobTH ${round(iobTHvirtual / iobTHtolerance * 100, 2)}U") From b332e594d5f2c3bf4a1a1da1af58431a7f5948cb Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 9 Mar 2024 16:58:14 +0100 Subject: [PATCH 21/38] AutoISFPlugin Several fixes and improvement of null management within autoISF --- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 9 +++-- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 38 +++++++++---------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 4cebdf738fa..6529f4953a2 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -296,8 +296,9 @@ class DetermineBasalAutoISF @Inject constructor( val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) val sens = - if (dynIsfMode) profile.variable_sens - else { + if (dynIsfMode) { + profile.variable_sens + } else { val profile_sens = round(profile.sens, 1) val adjusted_sens = round(profile.sens / sensitivityRatio, 1) if (adjusted_sens != profile_sens) { @@ -1043,8 +1044,8 @@ class DetermineBasalAutoISF @Inject constructor( if (dynIsfMode) { microBolus = Math.min(insulinReq * smb_ratio, maxBolus) // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun - val iobTHtolerance = 130 - val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000 * profile.max_iob * iobTH_reduction_ratio + val iobTHtolerance = 130.0 + val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000.0 * profile.max_iob * iobTH_reduction_ratio if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb == "fullLoop" || loop_wanted_smb == "enforced")) { microBolus = iobTHvirtual - iob_data.iob consoleError.add("Full loop capped SMB at ${round(microBolus, 2)} to not exceed $iobTHtolerance% of effective iobTH ${round(iobTHvirtual / iobTHtolerance * 100, 2)}U") diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 6b06748ea45..cdaf1b3ea59 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -142,8 +142,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) private val exerciseMode = SMBDefaults.exercise_mode private val highTemptargetRaisesSensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) - private var enableDynAps = true - override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) && enableDynAps + override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() @@ -190,7 +189,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( if (!preferences.get(BooleanKey.ApsUseDynamicSensitivity)) return Pair("OFF", null) val result = persistenceLayer.getApsResultCloseTo(timestamp) if (result?.variableSens != null) { - //aapsLogger.debug("calculateVariableIsf $caller DB ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${result.variableSens}") + aapsLogger.debug("calculateVariableIsf DB ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${result.variableSens}") return Pair("DB", result.variableSens) } val glucose = bg ?: glucoseStatusProvider.glucoseStatusData?.glucose ?: return Pair("GLUC", null) @@ -199,14 +198,13 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val key = timestamp - timestamp % T.mins(30).msecs() + glucose.toLong() val cached = dynIsfCache[key] if (cached != null && timestamp < dateUtil.now()) { - //aapsLogger.debug("calculateVariableIsf $caller HIT ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $cached") + aapsLogger.debug("calculateVariableIsf HIT ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $cached") return Pair("HIT", cached) } // no cached result found, let's calculate the value - enableDynAps = false // disable supportsDynamicIsf feature to get profile ISF value - val sensitivity = (autoISF(timestamp) ?: 1.0) * profile.getIsfMgdlTimeFromMidnight(MidnightUtils.secondsFromMidnight(timestamp)) - aapsLogger.debug("XXXXX $sensitivity ${profile.getIsfMgdlTimeFromMidnight(MidnightUtils.secondsFromMidnight(timestamp))}") - enableDynAps = true // enable supportsDynamicIsf feature after calculation + val autoIsfTimestamp = autoISF(timestamp, profile) + val sensitivity = autoIsfTimestamp + aapsLogger.debug("XXXXX ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $sensitivity ${profile.getProfileIsfMgdl()} ${autoIsfTimestamp}") dynIsfCache.put(key, sensitivity) if (dynIsfCache.size() > 1000) dynIsfCache.clear() return Pair("CALC", sensitivity) @@ -273,7 +271,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } var autosensResult = AutosensResult() - var variableSensitivity = 0.0 + var variableSensitivity = profile.getProfileIsfMgdl() val sens = profile.getIsfMgdl("OpenAPSAutoISFPlugin") if (constraintsChecker.isAutosensModeEnabled().value()) { @@ -291,8 +289,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( var microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() if (dynIsfMode) { - consoleError = mutableListOf() - variableSensitivity = autoISF(now) ?: 1.0 + consoleError = mutableListOf() + variableSensitivity = autoISF(now, profile) } val oapsProfile = OapsProfile( dia = 0.0, // not used @@ -474,14 +472,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( fun convert_bg(value: Double): String = profileUtil.fromMgdlToStringInUnits(value).replace("-0.0", "0.0") - fun autoISF(currentTime: Long): Double? { - //origin_sens: String, oapsProfile: OapsProfile, sensitivityRatio: Double, loop_wanted_smb: String): Double? { - val profile = profileFunction.getProfile() - val sens = profile?.getIsfMgdl("OpenAPSAutoISFPlugin") + fun autoISF(currentTime: Long, profile: Profile): Double { + val sens = profile.getProfileIsfMgdl() val glucose_status = glucoseStatusProvider.glucoseStatusData val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights) val normalTarget = 100 - if (!dynIsfMode || sens == null || glucose_status == null) { + if (!dynIsfMode || glucose_status == null) { consoleError.add("autoISF disabled in Preferences") consoleError.add("----------------------------------") consoleError.add("end autoISF") @@ -496,7 +492,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( isTempTarget = true target_bg = hardLimits.verifyHardLimits(tempTarget.target(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TEMP_TARGET_BG[0], HardLimits.LIMIT_TEMP_TARGET_BG[1]) } - var sensitivityRatio = 1.0 + var sensitivityRatio: Double var origin_sens = "" val low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens) if (high_temptarget_raises_sensitivity && isTempTarget && target_bg > normalTarget @@ -535,7 +531,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") if (autosensData == null) { rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) - return null + return sens } autosensData.autosensResult } else autosensResult.sensResult = "autosens disabled" @@ -547,7 +543,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( var pp_ISF = 1.0 var delta_ISF = 1.0 var acce_ISF = 1.0 - var acce_weight: Double = 1.0 + var acce_weight = 1.0 val bg_off = target_bg + 10.0 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 // calculate acce_ISF from bg acceleration and adapt ISF accordingly @@ -598,8 +594,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val bg_ISF = 1 + interpolate(100 - bg_off, "bg") consoleError.add("bg_ISF adaptation is ${round(bg_ISF, 2)}") - var liftISF = 1.0 - var final_ISF = 1.0 + var liftISF: Double + var final_ISF: Double if (bg_ISF < 1.0) { liftISF = min(bg_ISF, acce_ISF) if (acce_ISF > 1.0) { From 8f5e1e9b79e75098f991252d94c365786eef574c Mon Sep 17 00:00:00 2001 From: Philoul Date: Sat, 9 Mar 2024 17:08:10 +0100 Subject: [PATCH 22/38] AutoISFPlugin Remove temporary debug --- .../app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index cdaf1b3ea59..06b57890f7e 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -204,7 +204,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // no cached result found, let's calculate the value val autoIsfTimestamp = autoISF(timestamp, profile) val sensitivity = autoIsfTimestamp - aapsLogger.debug("XXXXX ${dateUtil.dateAndTimeAndSecondsString(timestamp)} $sensitivity ${profile.getProfileIsfMgdl()} ${autoIsfTimestamp}") + //aapsLogger.debug("XXXXX ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${profile.getProfileIsfMgdl()} -> ${autoIsfTimestamp}") dynIsfCache.put(key, sensitivity) if (dynIsfCache.size() > 1000) dynIsfCache.clear() return Pair("CALC", sensitivity) From 90d146a133eda861795538ba086780ce97e71ab0 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Tue, 26 Mar 2024 13:01:27 +0100 Subject: [PATCH 23/38] initialize AutoISFPlugin unit tests --- .../OpenAPSAutoISFPluginTest.kt | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt new file mode 100644 index 00000000000..65ba04c6927 --- /dev/null +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -0,0 +1,172 @@ +package app.aaps.plugins.aps.openAPSAutoISF + +import android.content.SharedPreferences +import app.aaps.core.data.aps.SMBDefaults +import app.aaps.core.data.model.GlucoseUnit +import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck +import app.aaps.core.interfaces.constraints.ConstraintsChecker +import app.aaps.core.interfaces.db.PersistenceLayer +import app.aaps.core.interfaces.iob.GlucoseStatusProvider +import app.aaps.core.interfaces.profiling.Profiler +import app.aaps.core.interfaces.stats.TddCalculator +import app.aaps.core.interfaces.ui.UiInteraction +import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.keys.AdaptiveIntentPreference +import app.aaps.core.keys.BooleanKey +import app.aaps.core.keys.DoubleKey +import app.aaps.core.keys.IntKey +import app.aaps.core.keys.UnitDoubleKey +import app.aaps.core.validators.AdaptiveDoublePreference +import app.aaps.core.validators.AdaptiveIntPreference +import app.aaps.core.validators.AdaptiveSwitchPreference +import app.aaps.core.validators.AdaptiveUnitPreference +import app.aaps.shared.tests.TestBaseWithProfile +import com.google.common.truth.Truth.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mock + +class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { + + @Mock lateinit var constraintChecker: ConstraintsChecker + @Mock lateinit var persistenceLayer: PersistenceLayer + @Mock lateinit var glucoseStatusProvider: GlucoseStatusProvider + @Mock lateinit var determineBasalSMB: DetermineBasalAutoISF + @Mock lateinit var sharedPrefs: SharedPreferences + @Mock lateinit var bgQualityCheck: BgQualityCheck + @Mock lateinit var tddCalculator: TddCalculator + @Mock lateinit var uiInteraction: UiInteraction + @Mock lateinit var profiler: Profiler + private lateinit var openAPSAutoISFPlugin: OpenAPSAutoISFPlugin + + init { + addInjector { + if (it is AdaptiveDoublePreference) { + it.profileUtil = profileUtil + it.preferences = preferences + it.sharedPrefs = sharedPrefs + } + if (it is AdaptiveIntPreference) { + it.profileUtil = profileUtil + it.preferences = preferences + it.sharedPrefs = sharedPrefs + it.config = config + } + if (it is AdaptiveIntentPreference) { + it.preferences = preferences + it.sharedPrefs = sharedPrefs + } + if (it is AdaptiveUnitPreference) { + it.profileUtil = profileUtil + it.preferences = preferences + it.sharedPrefs = sharedPrefs + } + if (it is AdaptiveSwitchPreference) { + it.preferences = preferences + it.sharedPrefs = sharedPrefs + it.config = config + } + } + } + + @BeforeEach fun prepare() { + openAPSAutoISFPlugin = OpenAPSAutoISFPlugin( + injector, aapsLogger, rxBus, constraintChecker, rh, profileFunction, profileUtil, config, activePlugin, + iobCobCalculator, hardLimits, preferences, dateUtil, processedTbrEbData, persistenceLayer, glucoseStatusProvider, + bgQualityCheck, uiInteraction, determineBasalSMB, profiler + ) + } + + @Test + fun specialEnableConditionTest() { + assertThat(openAPSAutoISFPlugin.specialEnableCondition()).isTrue() + } + + @Test + fun specialShowInListConditionTest() { + assertThat(openAPSAutoISFPlugin.specialShowInListCondition()).isTrue() + } + + @Test + fun preferenceScreenTest() { + val screen = preferenceManager.createPreferenceScreen(context) + openAPSAutoISFPlugin.addPreferenceScreen(preferenceManager, screen, context, null) + assertThat(screen.preferenceCount).isGreaterThan(0) + } + + @Test + fun withinISFlimitsTest() { + var autoIsfMin = 0.7 + var autoIsfMax = 1.2 + var sens = 1.1 // from Autosens + val origin_sens = "" + var ttSet = false + var exerciseMode = false + var targetBg = 120.0 + val normalTarget = 100 + assertThat(openAPSAutoISFPlugin.withinISFlimits(1.7, autoIsfMin, autoIsfMax, sens, origin_sens, ttSet, exerciseMode, targetBg, normalTarget)).isEqualTo(1.2) // upper limit + assertThat(openAPSAutoISFPlugin.withinISFlimits(0.5, autoIsfMin, autoIsfMax, sens, origin_sens, ttSet, exerciseMode, targetBg, normalTarget)).isEqualTo(0.7) // lower limit + sens = 1.5 // from Autosens + assertThat(openAPSAutoISFPlugin.withinISFlimits(1.7, autoIsfMin, autoIsfMax, sens, origin_sens, ttSet, exerciseMode, targetBg, normalTarget)).isEqualTo(1.5) // autosens 1.5 wins + sens = 0.5 // from Autosens + assertThat(openAPSAutoISFPlugin.withinISFlimits(0.5, autoIsfMin, autoIsfMax, sens, origin_sens, ttSet, exerciseMode, targetBg, normalTarget)).isEqualTo(0.5) // autosens 0.5 wins + exerciseMode = true + ttSet = true + assertThat(openAPSAutoISFPlugin.withinISFlimits(0.5, autoIsfMin, autoIsfMax, sens, origin_sens, ttSet, exerciseMode, targetBg, normalTarget)).isEqualTo(0.35) // exercise mode + } + + @Test + fun determine_varSMBratioTest() { + val smb_delivery_ratio = 0.3 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) + val smb_delivery_ratio_min = 0.4 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) + val smb_delivery_ratio_max = 0.6 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) + val smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) + val smbMaxRangeExtension = 2.0 //preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + val oapsProfile = OapsProfile( + dia = 0.0, // not used + min_5m_carbimpact = 0.0, // not used + max_iob = 8.0, //constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), + max_daily_basal = 0.4, //profile.getMaxDailyBasal(), + max_basal = 0.4, //constraintsChecker.getMaxBasalAllowed(profile).also { inputConstraints.copyReasons(it) }.value(), + min_bg = 90.0, + max_bg = 90.0, + target_bg = 90.0, + carb_ratio = 10.0, //profile.getIc(), + sens = 100.0, //sens, + autosens_adjust_targets = false, // not used + max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), + current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), + lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), + high_temptarget_raises_sensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens), //exerciseMode || highTemptargetRaisesSensitivity, //was false, + low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, + sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), + resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), + adv_target_adjustments = SMBDefaults.adv_target_adjustments, + exercise_mode = SMBDefaults.exercise_mode, + half_basal_exercise_target = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), + maxCOB = SMBDefaults.maxCOB, + skip_neutral_temps = false, //pump.setNeutralTempAtFullHour(), + remainingCarbsCap = SMBDefaults.remainingCarbsCap, + enableUAM = true, //constraintsChecker.isUAMEnabled().also { inputConstraints.copyReasons(it) }.value(), + A52_risk_enable = SMBDefaults.A52_risk_enable, + SMBInterval = preferences.get(IntKey.ApsMaxSmbFrequency), + enableSMB_with_COB = preferences.get(BooleanKey.ApsUseSmbWithCob), //smbEnabled && + enableSMB_with_temptarget = preferences.get(BooleanKey.ApsUseSmbWithLowTt), //smbEnabled && + allowSMB_with_high_temptarget = preferences.get(BooleanKey.ApsUseSmbWithHighTt), //smbEnabled && + enableSMB_always = preferences.get(BooleanKey.ApsUseSmbAlways), //smbEnabled && && advancedFiltering, + enableSMB_after_carbs = preferences.get(BooleanKey.ApsUseSmbAfterCarbs), //smbEnabled && && advancedFiltering, + maxSMBBasalMinutes = preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb), + maxUAMSMBBasalMinutes = preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb), + bolus_increment = 0.1, //pump.pumpDescription.bolusStep, + carbsReqThreshold = preferences.get(IntKey.ApsCarbsRequestThreshold), + current_basal = activePlugin.activePump.baseBasalRate, + temptargetSet = false, + autosens_max = preferences.get(DoubleKey.AutosensMax), + out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", + variable_sens = 100.0, //variableSensitivity, + insulinDivisor = 0, + TDD = 0.0 + ) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(oapsProfile,100, 90.0, "fullLoop")).isEqualTo(0.5) + } +} From cfc1baa0283a8c50798e231bf28d5f4389922cf8 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Mon, 1 Apr 2024 15:26:07 +0200 Subject: [PATCH 24/38] fix bugs in algorithm and reporting --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 2 +- .../kotlin/app/aaps/core/keys/BooleanKey.kt | 1 + .../kotlin/app/aaps/core/keys/DoubleKey.kt | 4 +- core/keys/src/main/res/values/keys.xml | 1 + .../app/aaps/plugins/aps/OpenAPSFragment.kt | 2 +- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 100 ++++++----- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 160 +++++++++++++----- plugins/aps/src/main/res/values/strings.xml | 12 +- 8 files changed, 188 insertions(+), 94 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 8cab162a7e1..eddab4a231e 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -795,7 +795,7 @@ class ReplayApsResultsTest @Inject constructor() { microBolusAllowed = determineBasalResult.microBolusAllowed, currentTime = currentTime, flatBGsDetected = determineBasalResult.flatBGsDetected, - dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights), + autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf), iob_threshold_percent = preferences.get(IntKey.ApsAutoIsfIobThPercent), smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension), profile_percentage = 100, diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt index d616013a9bd..0c6bcdd95b9 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt @@ -48,6 +48,7 @@ enum class BooleanKey( MaintenanceEnableFabric(R.string.key_enable_fabric, true, defaultedBySM = true, hideParentScreenIfHidden = true), ApsAutoIsfHighTtRaisesSens(R.string.key_high_temptarget_raises_sensitivity, false, defaultedBySM = true), ApsAutoIsfLowTtLowersSens(R.string.key_low_temptarget_lowers_sensitivity, false, defaultedBySM = true), + ApsUseAutoIsf(R.string.key_use_autoISF, false, defaultedBySM = true), ApsUseAutoIsfWeights(R.string.key_enable_autoISF, false, defaultedBySM = true), ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false, defaultedBySM = true), ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false, defaultedBySM = true), diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt index 2d718c46024..63a4332e21d 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/DoubleKey.kt @@ -34,8 +34,8 @@ enum class DoubleKey( AbsorptionMaxTime(R.string.key_absorption_maxtime, 6.0, 4.0, 10.0), AutosensMin(R.string.key_openaps_autosens_min, 0.7, 0.1, 1.0, defaultedBySM = true, hideParentScreenIfHidden = true), AutosensMax(R.string.key_openaps_autosens_max, 1.2, 0.5, 3.0, defaultedBySM = true), - ApsAutoIsfMin(R.string.key_openapsama_autoISF_min, 1.0, 0.3, 1.0, defaultedBySM = false), - ApsAutoIsfMax(R.string.key_openapsama_autoISF_max, 1.0, 1.0, 5.0, defaultedBySM = false), + ApsAutoIsfMin(R.string.key_openapsama_autoISF_min, 1.0, 0.3, 1.0, defaultedBySM = true), + ApsAutoIsfMax(R.string.key_openapsama_autoISF_max, 1.0, 1.0, 3.0, defaultedBySM = true), ApsAutoIsfBgAccelWeight(R.string.key_openapsama_bgAccel_ISF_weight, 0.0, 0.0, 1.0, defaultedBySM = true), ApsAutoIsfBgBrakeWeight(R.string.key_openapsama_bgBrake_ISF_weight, 0.0, 0.0, 1.0, defaultedBySM = true), ApsAutoIsfLowBgWeight(R.string.key_openapsama_lower_ISFrange_weight, 0.0, 0.0, 2.0, defaultedBySM = true), diff --git a/core/keys/src/main/res/values/keys.xml b/core/keys/src/main/res/values/keys.xml index 2927dfffa82..b5479f8b21e 100644 --- a/core/keys/src/main/res/values/keys.xml +++ b/core/keys/src/main/res/values/keys.xml @@ -109,6 +109,7 @@ link_to_docs + use_autoisf half_basal_exercise_target openapsama_enable_autoISF openapsama_enable_autoISF diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt index d2da2bf2ccc..d9fa0d25648 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt @@ -131,7 +131,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider { openAPSPlugin.lastAPSResult?.let { lastAPSResult -> binding.result.text = lastAPSResult.rawData().dataClassToHtml() binding.request.text = lastAPSResult.resultAsSpanned() - binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta", "corrSqu", "bgAcceleration")) + binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta", "corrSqu", "parabolaMinutes", "bgAcceleration")) binding.currenttemp.text = lastAPSResult.currentTemp?.dataClassToHtml() binding.iobdata.text = rh.gs(R.string.array_of_elements, lastAPSResult.iobData?.size) + "\n" + lastAPSResult.iob?.dataClassToHtml() binding.profile.text = lastAPSResult.oapsProfile?.dataClassToHtml() diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 6529f4953a2..2858b96a9c5 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -10,6 +10,7 @@ import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.profile.ProfileUtil +import app.aaps.plugins.aps.openAPSAutoISF.OpenAPSAutoISFPlugin import java.text.DecimalFormat import java.time.Instant import java.time.ZoneId @@ -146,17 +147,16 @@ class DetermineBasalAutoISF @Inject constructor( } - fun determine_basal( glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, - microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, dynIsfMode: Boolean, loop_wanted_smb: String, profile_percentage: Int, smb_ratio: Double, + microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, autoIsfMode: Boolean, loop_wanted_smb: String, profile_percentage: Int, smb_ratio: Double, smb_max_range_extension: Double, iob_threshold_percent: Int, auto_isf_console: MutableList ): RT { consoleError.clear() consoleLog.clear() var rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = dynIsfMode, + runningDynamicIsf = autoIsfMode, timestamp = currentTime, consoleLog = consoleLog, consoleError = consoleError @@ -225,13 +225,6 @@ class DetermineBasalAutoISF @Inject constructor( // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%), 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) val halfBasalTarget = profile.half_basal_exercise_target - if (dynIsfMode) { - consoleError.add("---------------------------------------------------------") - consoleError.add(" Auto ISF 3.0") - consoleError.add("---------------------------------------------------------") - consoleError.addAll(auto_isf_console) - } - if (high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) { @@ -254,13 +247,18 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = autosens_data.ratio consoleError.add("Autosens ratio: $sensitivityRatio; ") } - val iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; + var iobTH_reduction_ratio = 1.0 + var use_iobTH = false + if (iob_threshold_percent != 100) { + iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; + use_iobTH = true + } basal = profile.current_basal * sensitivityRatio basal = round_basal(basal) if (basal != profile_current_basal) - consoleError.add("Adjusting basal from $profile_current_basal to $basal; ") + consoleError.add("Adjusting basal from $profile_current_basal to $basal;") else - consoleError.add("Basal unchanged: $basal; ") + consoleError.add("Basal unchanged: $basal;") // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120 if (profile.temptargetSet) { @@ -274,9 +272,9 @@ class DetermineBasalAutoISF @Inject constructor( // don't allow target_bg below 80 new_target_bg = max(80.0, new_target_bg) if (target_bg == new_target_bg) - consoleLog.add("target_bg unchanged: $new_target_bg; ") + consoleError.add("target_bg unchanged: $new_target_bg; ") else - consoleLog.add("target_bg from $target_bg to $new_target_bg; ") + consoleError.add("target_bg from $target_bg to $new_target_bg; ") target_bg = new_target_bg } @@ -295,21 +293,44 @@ class DetermineBasalAutoISF @Inject constructor( val minAvgDelta = min(glucose_status.shortAvgDelta, glucose_status.longAvgDelta) val maxDelta = max(glucose_status.delta, max(glucose_status.shortAvgDelta, glucose_status.longAvgDelta)) + val profile_sens = round(profile.sens, 1) + val adjusted_sens = round(profile.sens / sensitivityRatio, 1) + if (adjusted_sens != profile_sens) { + consoleError.add("ISF from $profile_sens to $adjusted_sens") + } else { + consoleError.add("ISF unchanged: $adjusted_sens") + } val sens = - if (dynIsfMode) { + if (autoIsfMode) { profile.variable_sens } else { - val profile_sens = round(profile.sens, 1) - val adjusted_sens = round(profile.sens / sensitivityRatio, 1) - if (adjusted_sens != profile_sens) { - consoleLog.add("ISF from $profile_sens to $adjusted_sens") - } else { - consoleLog.add("ISF unchanged: $adjusted_sens") - } adjusted_sens //console.log(" (autosens ratio "+sensitivityRatio+")"); } - consoleError.add("CR:${profile.carb_ratio}") + consoleError.add("CR: ${profile.carb_ratio}") + + if (autoIsfMode) { + consoleError.add("----------------------------------") + consoleError.add("start AutoISF 3.0") + consoleError.add("----------------------------------") + consoleError.addAll(auto_isf_console) + } + // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun + val iobTHtolerance = 130.0 + val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000.0 * profile.max_iob * iobTH_reduction_ratio + //var loop_wanted_smb = loop_smb(microBolusAllowed, profile, iob_data, use_iobTH, iobTHvirtual/iobTHtolerance*100.0); + var enableSMB = false; + if (microBolusAllowed && loop_wanted_smb != "AAPS") { + if ( loop_wanted_smb=="enforced" || loop_wanted_smb=="fullLoop" ) { // otherwise FL switched SMB off + enableSMB = true; + } + } else { enableSMB = enable_smb( + profile, + microBolusAllowed, + meal_data, + target_bg + ) + } //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone val bgi = round((-iob_data.activity * sens * 5), 2) @@ -327,7 +348,7 @@ class DetermineBasalAutoISF @Inject constructor( // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity val naive_eventualBG = - if (dynIsfMode) + if (autoIsfMode) round(bg - (iob_data.iob * sens), 0) else { if (iob_data.iob > 0) round(bg - (iob_data.iob * sens), 0) @@ -346,17 +367,17 @@ class DetermineBasalAutoISF @Inject constructor( // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedMinBG, don’t use it //console.error("naive_eventualBG:",naive_eventualBG+", eventualBG:",eventualBG); if (eventualBG > adjustedMinBG && naive_eventualBG > adjustedMinBG && min_bg > adjustedMinBG) { - consoleLog.add("Adjusting targets for high BG: min_bg from $min_bg to $adjustedMinBG; ") + consoleError.add("Adjusting targets for high BG: min_bg from $min_bg to $adjustedMinBG; ") min_bg = adjustedMinBG } else { - consoleLog.add("min_bg unchanged: $min_bg; ") + consoleError.add("min_bg unchanged: $min_bg; ") } // if eventualBG, naive_eventualBG, and target_bg aren't all above adjustedTargetBG, don’t use it if (eventualBG > adjustedTargetBG && naive_eventualBG > adjustedTargetBG && target_bg > adjustedTargetBG) { - consoleLog.add("target_bg from $target_bg to $adjustedTargetBG; ") + consoleError.add("target_bg from $target_bg to $adjustedTargetBG; ") target_bg = adjustedTargetBG } else { - consoleLog.add("target_bg unchanged: $target_bg; ") + consoleError.add("target_bg unchanged: $target_bg; ") } // if eventualBG, naive_eventualBG, and max_bg aren't all above adjustedMaxBG, don’t use it if (eventualBG > adjustedMaxBG && naive_eventualBG > adjustedMaxBG && max_bg > adjustedMaxBG) { @@ -383,7 +404,7 @@ class DetermineBasalAutoISF @Inject constructor( rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = dynIsfMode, + runningDynamicIsf = autoIsfMode, timestamp = currentTime, bg = bg, tick = tick, @@ -410,7 +431,7 @@ class DetermineBasalAutoISF @Inject constructor( ZTpredBGs.add(bg) UAMpredBGs.add(bg) - var enableSMB = if (dynIsfMode) microBolusAllowed else enable_smb(profile, microBolusAllowed, meal_data, target_bg) // pulled ahead for autoISF + //var enableSMB = if (autoIsfMode) microBolusAllowed else enable_smb(profile, microBolusAllowed, meal_data, target_bg) // pulled ahead for autoISF // enable UAM (if enabled in preferences) val enableUAM = profile.enableUAM @@ -659,7 +680,7 @@ class DetermineBasalAutoISF @Inject constructor( } consoleError.add("UAM Impact: $uci mg/dL per 5m; UAM Duration: $UAMduration hours") - consoleLog.add("EventualBG is $eventualBG ;") + consoleError.add("EventualBG is $eventualBG ;") minIOBPredBG = max(39.0, minIOBPredBG) minCOBPredBG = max(39.0, minCOBPredBG) @@ -744,12 +765,12 @@ class DetermineBasalAutoISF @Inject constructor( // make sure minPredBG isn't higher than avgPredBG minPredBG = min(minPredBG, avgPredBG) - consoleLog.add("minPredBG: $minPredBG minIOBPredBG: $minIOBPredBG minZTGuardBG: $minZTGuardBG") + consoleError.add("minPredBG: $minPredBG minIOBPredBG: $minIOBPredBG minZTGuardBG: $minZTGuardBG") if (minCOBPredBG < 999) { - consoleLog.add(" minCOBPredBG: $minCOBPredBG") + consoleError.add(" minCOBPredBG: $minCOBPredBG") } if (minUAMPredBG < 999) { - consoleLog.add(" minUAMPredBG: $minUAMPredBG") + consoleError.add(" minUAMPredBG: $minUAMPredBG") } consoleError.add(" avgPredBG: $avgPredBG COB: ${meal_data.mealCOB} / ${meal_data.carbs}") // But if the COB line falls off a cliff, don't trust UAM too much: @@ -824,8 +845,8 @@ class DetermineBasalAutoISF @Inject constructor( maxDeltaPercentage = 0.3 } if ( maxDelta > maxDeltaPercentage * bg ) { - consoleError.add("maxDelta ${convert_bg(maxDelta)} > $maxDeltaPercentage% of BG ${convert_bg(bg)} - disabling SMB") - rT.reason.append("maxDelta " + convert_bg(maxDelta) + " > " + maxDeltaPercentage + "% of BG " + convert_bg(bg) + ": SMB disabled; ") + consoleError.add("maxDelta ${convert_bg(maxDelta)} > ${100*maxDeltaPercentage}% of BG ${convert_bg(bg)} - disabling SMB") + rT.reason.append("maxDelta " + convert_bg(maxDelta) + " > " + 100*maxDeltaPercentage + "% of BG " + convert_bg(bg) + ": SMB disabled; ") enableSMB = false } @@ -1041,11 +1062,8 @@ class DetermineBasalAutoISF @Inject constructor( val roundSMBTo = 1 / profile.bolus_increment //var microBolus: Double var microBolus = Math.floor(Math.min(insulinReq / 2, maxBolus) * roundSMBTo) / roundSMBTo - if (dynIsfMode) { + if (autoIsfMode) { microBolus = Math.min(insulinReq * smb_ratio, maxBolus) - // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun - val iobTHtolerance = 130.0 - val iobTHvirtual = iob_threshold_percent * iobTHtolerance / 10000.0 * profile.max_iob * iobTH_reduction_ratio if (microBolus > iobTHvirtual - iob_data.iob && (loop_wanted_smb == "fullLoop" || loop_wanted_smb == "enforced")) { microBolus = iobTHvirtual - iob_data.iob consoleError.add("Full loop capped SMB at ${round(microBolus, 2)} to not exceed $iobTHtolerance% of effective iobTH ${round(iobTHvirtual / iobTHtolerance * 100, 2)}U") diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index c58b5f9b504..9846c11d3c4 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -119,6 +119,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( override var lastAPSResult: DetermineBasalResult? = null private var consoleError = mutableListOf() + val autoIsfWeights = preferences.get(BooleanKey.ApsUseAutoIsfWeights) private val autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax) private val autoISF_min = preferences.get(DoubleKey.ApsAutoIsfMin) private val bgAccel_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight) @@ -141,7 +142,11 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) private val exerciseMode = SMBDefaults.exercise_mode private val highTemptargetRaisesSensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) - override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsfWeights) + val profile = profileFunction.getProfile() + private val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 + val normalTarget = 100 + + override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() @@ -247,7 +252,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // End of check, start gathering data - val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights) + val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() @@ -274,7 +279,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val sens = profile.getIsfMgdl("OpenAPSAutoISFPlugin") if (constraintsChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSAutoISFPlugin") if (autosensData == null) { rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) return @@ -285,9 +290,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() val iobData = iobArray[0] val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 - var microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() + val microBolusAllowed = constraintsChecker.isSMBModeEnabled(ConstraintObject(tempBasalFallback.not(), aapsLogger)).also { inputConstraints.copyReasons(it) }.value() - if (dynIsfMode) { + if (autoIsfMode) { consoleError = mutableListOf() variableSensitivity = autoISF(now, profile) } @@ -336,16 +341,69 @@ open class OpenAPSAutoISFPlugin @Inject constructor( insulinDivisor = 0, TDD = 0.0 ) - val exercise_ratio = 1.0 - //todo calculate exercice ratio - val iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio; // later: * activityRatio; - val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, iobTH_reduction_ratio) - if (dynIsfMode) - microBolusAllowed = microBolusAllowed && loopWantedSmb != "AAPS" && (loopWantedSmb == "enforced" || loopWantedSmb == "fullLoop") - val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT + //done calculate exercise ratio + var exerciseRatio = 1.0 + var sensitivityRatio = 1.0 + var origin_sens = "" val target_bg = (minBg + maxBg) / 2 + if (highTemptargetRaisesSensitivity && isTempTarget && target_bg > normalTarget + || oapsProfile.low_temptarget_lowers_sensitivity && isTempTarget && target_bg < normalTarget ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + val c = (oapsProfile.half_basal_exercise_target - normalTarget).toDouble() + if (c * (c + target_bg-normalTarget) <= 0.0) { + sensitivityRatio = oapsProfile.autosens_max + } else { + sensitivityRatio = c / (c + target_bg - normalTarget) + // limit sensitivityRatio to profile.autosens_max (1.2x by default) + sensitivityRatio = min(sensitivityRatio, preferences.get(DoubleKey.AutosensMax)) + sensitivityRatio = round(sensitivityRatio, 2) + exerciseRatio = sensitivityRatio + origin_sens = "from TT modifier" + //consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") + } + } + var iobTH_reduction_ratio = 1.0 + var use_iobTH = false + val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) // make it dynamic? + if (iobThresholdPercent != 100) { + iobTH_reduction_ratio = profile_percentage / 100.0 * exerciseRatio + use_iobTH = true + } + // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun + val iobTHtolerance = 130.0 + val iobTHvirtual = iobThresholdPercent*iobTHtolerance/10000.0 * oapsProfile.max_iob * iobTH_reduction_ratio + val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, use_iobTH, iobTHvirtual/iobTHtolerance*100.0) + //if (autoIsfMode) + // microBolusAllowed = microBolusAllowed && loopWantedSmb != "AAPS" && (loopWantedSmb == "enforced" || loopWantedSmb == "fullLoop") + val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT val smbRatio = determine_varSMBratio(oapsProfile, glucoseStatus.glucose.toInt(), target_bg, loopWantedSmb) + var autoIsfExtras = """"low_temptarget_lowers_sensitivity":${preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens)}""" + autoIsfExtras += """, "enable_autoISF":$autoIsfWeights""" + autoIsfExtras += """, "autoISF_max":$autoISF_max""" + autoIsfExtras += """, "autoISF_min":$autoISF_min""" + autoIsfExtras += """, "bgAccel_ISF_weight":$bgAccel_ISF_weight""" + autoIsfExtras += """, "bgBrake_ISF_weight":$bgBrake_ISF_weight""" + autoIsfExtras += """, "enable_pp_ISF_always":$enable_pp_ISF_always""" + autoIsfExtras += """, "pp_ISF_hours":$pp_ISF_hours""" + autoIsfExtras += """, "pp_ISF_weight":$pp_ISF_weight""" + autoIsfExtras += """, "delta_ISFrange_weight":$delta_ISFrange_weight""" + autoIsfExtras += """, "lower_ISFrange_weight":$lower_ISFrange_weight""" + autoIsfExtras += """, "higher_ISFrange_weight":$higher_ISFrange_weight""" + autoIsfExtras += """, "enable_dura_ISF_with_COB":$enable_dura_ISF_with_COB""" + autoIsfExtras += """, "dura_ISF_weight":$dura_ISF_weight""" + autoIsfExtras += """, "smb_delivery_ratio":$smb_delivery_ratio""" + autoIsfExtras += """, "smb_delivery_ratio_min":$smb_delivery_ratio_min""" + autoIsfExtras += """, "smb_delivery_ratio_max":$smb_delivery_ratio_max""" + autoIsfExtras += """, "smb_delivery_ratio_bg_range":$smb_delivery_ratio_bg_range""" + autoIsfExtras += """, "smb_max_range_extension":$smbMaxRangeExtension""" + autoIsfExtras += """, "enableSMB_EvenOn_OddOff":$enableSMB_EvenOn_OddOff""" + autoIsfExtras += """, "enableSMB_EvenOn_OddOff_always":$enableSMB_EvenOn_OddOff_always""" + autoIsfExtras += """, "iob_threshold_percent":$iobThresholdPercent""" + autoIsfExtras += """, "profile_percentage":$profile_percentage""" + aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AutoISF <<<") aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") aapsLogger.debug(LTag.APS, "Current temp: $currentTemp") @@ -355,7 +413,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( aapsLogger.debug(LTag.APS, "Meal data: $mealData") aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") - aapsLogger.debug(LTag.APS, "AutoIsfMode: $dynIsfMode") + aapsLogger.debug(LTag.APS, "AutoIsfMode: $autoIsfMode") + aapsLogger.debug(LTag.APS, "AutoISF extras: {"+autoIsfExtras+"}") determineBasalAutoISF.determine_basal( glucose_status = glucoseStatus, @@ -367,7 +426,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( microBolusAllowed = microBolusAllowed, currentTime = now, flatBGsDetected = flatBGsDetected, - dynIsfMode = dynIsfMode, + autoIsfMode = autoIsfMode, loop_wanted_smb = loopWantedSmb, profile_percentage = profile_percentage, smb_ratio = smbRatio, @@ -474,12 +533,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( fun autoISF(currentTime: Long, profile: Profile): Double { val sens = profile.getProfileIsfMgdl() val glucose_status = glucoseStatusProvider.glucoseStatusData - val dynIsfMode = preferences.get(BooleanKey.ApsUseAutoIsfWeights) - val normalTarget = 100 - if (!dynIsfMode || glucose_status == null) { + val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) + + if (!autoIsfMode || !autoIsfWeights || glucose_status == null) { consoleError.add("autoISF disabled in Preferences") consoleError.add("----------------------------------") - consoleError.add("end autoISF") + consoleError.add("end AutoISF") consoleError.add("----------------------------------") return sens } @@ -504,32 +563,32 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val c = (halfBasalTarget - normalTarget).toDouble() if (c * (c + target_bg-normalTarget) <= 0.0) { sensitivityRatio = preferences.get(DoubleKey.AutosensMax) - consoleError.add("Sensitivity decrease for temp target of $target_bg limited by Autosens_max; ") + // consoleError.add("Sensitivity decrease for temp target of $target_bg limited by Autosens_max; ") } else { sensitivityRatio = c / (c + target_bg - normalTarget) // limit sensitivityRatio to profile.autosens_max (1.2x by default) sensitivityRatio = min(sensitivityRatio, preferences.get(DoubleKey.AutosensMax)) sensitivityRatio = round(sensitivityRatio, 2) - origin_sens = "from TT modifier" - consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") + origin_sens = " from TT modifier" + // consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") } } else { var autosensResult = AutosensResult() if (constraintsChecker.isAutosensModeEnabled().value()) { - iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")?.also { + iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSAutoISFPlugin")?.also { autosensResult = it.autosensResult } } else autosensResult.sensResult = "autosens disabled" sensitivityRatio = autosensResult.ratio - consoleError.add("Autosens ratio: $sensitivityRatio; ") + // consoleError.add("Autosens ratio: $sensitivityRatio; ") } // Todo include here exercise_ratio calculation val autosensResult = AutosensResult() if (constraintsChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSAutoISFPlugin") if (autosensData == null) { rxBus.send(EventResetOpenAPSGui(rh.gs(R.string.openaps_no_as_data))) return sens @@ -677,7 +736,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return round(sens / final_ISF, 1) } consoleError.add("----------------------------------") - consoleError.add("end autoISF") + consoleError.add("end AutoISF") consoleError.add("----------------------------------") return sens // nothing changed } @@ -784,12 +843,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } consoleError.add("final ISF factor is ${round(finalISF, 2)}" + origin_sens_final) consoleError.add("----------------------------------") - consoleError.add("end autoISF") + consoleError.add("end AutoISF") consoleError.add("----------------------------------") return finalISF } - fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, iobTH_reduction_ratio: Double): String { + fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, useIobTh: Boolean, iobThEffective: Double): String { if (!microBolusAllowed) { return "AAPS" // see message in enable_smb } @@ -820,36 +879,49 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } else { "odd " } - val iobTHeffective = iobThresholdPercent + + val iobThUser = preferences.get(IntKey.ApsAutoIsfIobThPercent) //iobThresholdPercent + if ( useIobTh ) { + val iobThPercent = round(iobThEffective/profile.max_iob*100.0, 0) + if ( iobThPercent == iobThUser.toDouble() ) { + consoleError.add("User setting iobTH=$iobThUser% not modulated") + } else { + consoleError.add("User setting iobTH=$iobThUser% modulated to ${iobThPercent.toInt()}% or ${round(iobThEffective,2)}U") + consoleError.add(" due to profile %, exercise mode or similar") + } + } else { + consoleError.add("User setting iobTH=100% disables iobTH method") + } + if (!evenTarget) { consoleError.add("SMB disabled; $msgType $target $msgUnits $msgEven $msgTail") - consoleError.add("Loop at minimum power") + consoleError.add("Loop allows minimal power") return "blocked" } else if (profile.max_iob == 0.0) { consoleError.add("SMB disabled because of max_iob=0") return "blocked" - } else if (iobTHeffective / 100.0 < iob_data_iob / (profile.max_iob * iobTH_reduction_ratio)) { - if (iobTH_reduction_ratio != 1.0) { - consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob * iobTH_reduction_ratio, 2)} due to profile % and/or exercise mode") - msg = "effective maxIOB ${round(profile.max_iob * iobTH_reduction_ratio, 2)}" - } else { - msg = "maxIOB ${profile.max_iob}" - } - consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is more than $iobTHeffective% of $msg") - consoleError.add("Full Loop capped"); - return "iobTH"; + } else if ( useIobTh && iobThEffective < iob_data_iob ) { + //if (iobTH_reduction_ratio != 1.0) { + // consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob * iobTH_reduction_ratio, 2)} due to profile % and/or exercise mode") + // msg = "effective maxIOB ${round(profile.max_iob * iobTH_reduction_ratio, 2)}" + //} else { + // msg = "maxIOB ${profile.max_iob}" + //} + consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is above effective iobTH $iobThEffective") + consoleError.add("Full Loop capped") + return "iobTH" } else { consoleError.add("SMB enabled; $msgType $target $msgUnits $msgEven $msgTail") if (profile.target_bg < 100) { // indirect assessment; later set it in GUI - consoleError.add("Loop at full power") + consoleError.add("Loop allows full power") return "fullLoop" // even number } else { - consoleError.add("Loop at medium power") + consoleError.add("Loop allows medium power") return "enforced" // even number } } } - consoleError.add("Full Loop disabled") + consoleError.add("Loop allows APS power level") return "AAPS" // leave it to standard AAPS } @@ -907,7 +979,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( initialExpandedChildrenCount = 0 addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsMaxBasal, dialogMessage = R.string.openapsma_max_basal_summary, title = R.string.openapsma_max_basal_title)) addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsSmbMaxIob, dialogMessage = R.string.openapssmb_max_iob_summary, title = R.string.openapssmb_max_iob_title)) - addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsfWeights, summary = R.string.autoISF_settings_summary, title = R.string.autoISF_settings_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutosens, title = R.string.openapsama_use_autosens)) //addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsDynIsfAdjustmentFactor, dialogMessage = R.string.dyn_isf_adjust_summary, title = R.string.dyn_isf_adjust_title)) addPreference(AdaptiveUnitPreference(ctx = context, unitKey = UnitDoubleKey.ApsLgsThreshold, dialogMessage = R.string.lgs_threshold_summary, title = R.string.lgs_threshold_title)) @@ -950,10 +1021,11 @@ open class OpenAPSAutoISFPlugin @Inject constructor( ) ) }) + addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsf, summary = R.string.use_autoISF_extensions_summary, title = R.string.use_autoISF_extensions_title)) addPreference(preferenceManager.createPreferenceScreen(context).apply { key = "auto_isf_settings" title = rh.gs(R.string.autoISF_settings_title) - summary = rh.gs(R.string.autoISF_settings_summary) + summary = "" //rh.gs(R.string.autoISF_settings_summary) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsfWeights, summary = R.string.openapsama_enable_autoISF, title = R.string.openapsama_enable_autoISF)) addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfMin, dialogMessage = R.string.openapsama_autoISF_min_summary, title = R.string.openapsama_autoISF_min)) addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsAutoIsfMax, dialogMessage = R.string.openapsama_autoISF_max_summary, title = R.string.openapsama_autoISF_max)) diff --git a/plugins/aps/src/main/res/values/strings.xml b/plugins/aps/src/main/res/values/strings.xml index 3753a87fef0..f1bbacf4282 100644 --- a/plugins/aps/src/main/res/values/strings.xml +++ b/plugins/aps/src/main/res/values/strings.xml @@ -203,14 +203,16 @@ smb delivery settings smb delivery settings: Set of options to increase the actual SMB size which can be delivered in situations where ISF was strengthened, i.e. fairly low ISF figure.\n\nUSE WITH CAUTION Full Loop Settings - Full Loop Settings: Adjust iobTH and total acce weights for meal types + Full Loop Settings: Adjust iobTH to limit IOB build up + Enable AutoISF extended functionalities + These include ISF modulation due to recent bg behaviour, alternative SMB enablers and support for Full Closed Loop Enable ISF adaptation by glucose behaviour - Default value: 1.2\nThis is a multiplier cap for autoISF to set a limit on how high the autoISF ratio can be, which in turn determines how low it can adjust ISF.\n\nWARNING: Be extremely careful when using values above 2.5 + Default value: 1.0\nThis is a multiplier cap for autoISF to set a limit on how high the autoISF ratio can be, which in turn determines how low it can adjust ISF.\n\nWARNING: Be extremely careful when using values above 2.5 Default value: 1.0\nThis 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. Default value: 0.0\nThis is the rate at which autoISF grows per hour assuming bg is twice the target. With a value of 1.0 it will have reduced ISF to 50% after 1 hour of bg at twice the target.\n\nWith 0.0 the effect of autoISF is effectively disabled. - Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF if glucose is below target. \n\nWith 0.0 the effect is effectively disabled. - Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF if glucose is above target. \n\nWith 0.0 the effect is effectively disabled. - Default value: 0.0\nThis is the weight applied to the polygon which adapats ISF for higher deltas. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapts ISF if glucose is below target. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapts ISF if glucose is above target. \n\nWith 0.0 the effect is effectively disabled. + Default value: 0.0\nThis is the weight applied to the polygon which adapts ISF for higher deltas. \n\nWith 0.0 the effect is effectively disabled. Default value: 0.0\nThis is the weight applied to the linear slope while glucose rises and which adapts ISF. \n\nWith 0.0 this contribution is effectively disabled. Default value: 3\nThis is the duration in hours how long after a meal the effect will be active. \n\nAAPS will delete carb timing after 10 hours latest no matter what you enter. Enable pp_ISF postprandial all day From f6c4ec72d437e0e5cdaf3fdf584bf254efbcc767 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Mon, 1 Apr 2024 19:10:59 +0200 Subject: [PATCH 25/38] reactivate other unit tests --- .../androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index eddab4a231e..0fb1e5dfb11 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -98,11 +98,11 @@ class ReplayApsResultsTest @Inject constructor() { OpenAPSAMAPlugin::class.simpleName -> amas++ } when (algorithm) { - //OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) + OpenAPSSMBPlugin::class.simpleName -> testOpenAPSSMB(filename, input, output, injector) "OpenAPSSMBAutoISFPlugin" -> testOpenAPSSMBAutoISF(filename, input, output, injector) - //"OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) - //OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) - //else -> error("Unsupported") + "OpenAPSSMBDynamicISFPlugin" -> testOpenAPSSMBDynamicISF(filename, input, output, injector) + OpenAPSAMAPlugin::class.simpleName -> testOpenAPSAMA(filename, input, output, injector) + else -> error("Unsupported") } } aapsLogger.info(LTag.CORE, "\n**********\nAMA: $amas\nSMB: $smbs\nDynISFs: $dynisfs\nAutoISFs: $autoisfs\nJS time: $jsTime\nKT time: $ktTime\n**********") From fbbaaf57146b3fa91c397217df351ba3110b5644 Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Tue, 16 Apr 2024 02:57:26 +0200 Subject: [PATCH 26/38] fix updating variables and minor adaptations --- .../kotlin/app/aaps/core/keys/BooleanKey.kt | 2 +- .../app/aaps/plugins/aps/OpenAPSFragment.kt | 2 +- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 12 +-- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 91 ++++++++++--------- 4 files changed, 55 insertions(+), 52 deletions(-) diff --git a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt index 0c6bcdd95b9..b9e48686ae5 100644 --- a/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt +++ b/core/keys/src/main/kotlin/app/aaps/core/keys/BooleanKey.kt @@ -48,7 +48,7 @@ enum class BooleanKey( MaintenanceEnableFabric(R.string.key_enable_fabric, true, defaultedBySM = true, hideParentScreenIfHidden = true), ApsAutoIsfHighTtRaisesSens(R.string.key_high_temptarget_raises_sensitivity, false, defaultedBySM = true), ApsAutoIsfLowTtLowersSens(R.string.key_low_temptarget_lowers_sensitivity, false, defaultedBySM = true), - ApsUseAutoIsf(R.string.key_use_autoISF, false, defaultedBySM = true), + ApsUseAutoIsf(R.string.key_use_autoISF, false), ApsUseAutoIsfWeights(R.string.key_enable_autoISF, false, defaultedBySM = true), ApsAutoIsfPpAlways(R.string.key_enable_postprandial_ISF_always, false, defaultedBySM = true), ApsAutoIsfDuraAfterCarbs(R.string.key_enable_dura_ISF_with_COB, false, defaultedBySM = true), diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt index d9fa0d25648..f7fe7035844 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt @@ -131,7 +131,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider { openAPSPlugin.lastAPSResult?.let { lastAPSResult -> binding.result.text = lastAPSResult.rawData().dataClassToHtml() binding.request.text = lastAPSResult.resultAsSpanned() - binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta", "corrSqu", "parabolaMinutes", "bgAcceleration")) + binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta")) binding.currenttemp.text = lastAPSResult.currentTemp?.dataClassToHtml() binding.iobdata.text = rh.gs(R.string.array_of_elements, lastAPSResult.iobData?.size) + "\n" + lastAPSResult.iob?.dataClassToHtml() binding.profile.text = lastAPSResult.oapsProfile?.dataClassToHtml() diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 2858b96a9c5..3f86d0b8bcd 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -156,7 +156,7 @@ class DetermineBasalAutoISF @Inject constructor( consoleLog.clear() var rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = autoIsfMode, + runningDynamicIsf = false, // autoIsfMode, timestamp = currentTime, consoleLog = consoleLog, consoleError = consoleError @@ -218,7 +218,7 @@ class DetermineBasalAutoISF @Inject constructor( var max_bg = profile.max_bg var sensitivityRatio = 1.0 - var origin_sens = "" + // var origin_sens = "" var exercise_ratio = 1.0 val high_temptarget_raises_sensitivity = profile.exercise_mode || profile.high_temptarget_raises_sensitivity val normalTarget = 100 // evaluate high/low temptarget against 100, not scheduled target (which might change) @@ -240,7 +240,7 @@ class DetermineBasalAutoISF @Inject constructor( sensitivityRatio = min(sensitivityRatio, profile.autosens_max) sensitivityRatio = round(sensitivityRatio, 2) exercise_ratio = sensitivityRatio - origin_sens = "from TT modifier" + // origin_sens = "from TT modifier" consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") } } else { @@ -248,10 +248,10 @@ class DetermineBasalAutoISF @Inject constructor( consoleError.add("Autosens ratio: $sensitivityRatio; ") } var iobTH_reduction_ratio = 1.0 - var use_iobTH = false + // var use_iobTH = false if (iob_threshold_percent != 100) { iobTH_reduction_ratio = profile_percentage / 100.0 * exercise_ratio ; // later: * activityRatio; - use_iobTH = true + // use_iobTH = true } basal = profile.current_basal * sensitivityRatio basal = round_basal(basal) @@ -404,7 +404,7 @@ class DetermineBasalAutoISF @Inject constructor( rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = autoIsfMode, + runningDynamicIsf = false, // autoIsfMode, timestamp = currentTime, bg = bg, tick = tick, diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 9846c11d3c4..8bb088c7472 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -119,31 +119,31 @@ open class OpenAPSAutoISFPlugin @Inject constructor( override var lastAPSResult: DetermineBasalResult? = null private var consoleError = mutableListOf() - val autoIsfWeights = preferences.get(BooleanKey.ApsUseAutoIsfWeights) - private val autoISF_max = preferences.get(DoubleKey.ApsAutoIsfMax) - private val autoISF_min = preferences.get(DoubleKey.ApsAutoIsfMin) - private val bgAccel_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight) - private val bgBrake_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight) - private val enable_pp_ISF_always = preferences.get(BooleanKey.ApsAutoIsfPpAlways) - private val pp_ISF_hours = preferences.get(IntKey.ApsAutoIsfPpIsfHours) - private val pp_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfPpWeight) - private val delta_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfDeltaWeight) - private val lower_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfLowBgWeight) - private val higher_ISFrange_weight = preferences.get(DoubleKey.ApsAutoIsfHighBgWeight) - private val enable_dura_ISF_with_COB = preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs) - private val dura_ISF_weight = preferences.get(DoubleKey.ApsAutoIsfDuraWeight) - private val smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) - private val smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) - private val smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) - private val smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) - val smbMaxRangeExtension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) - private val enableSMB_EvenOn_OddOff = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt) // for TT - private val enableSMB_EvenOn_OddOff_always = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt) // for profile target - val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) - private val exerciseMode = SMBDefaults.exercise_mode - private val highTemptargetRaisesSensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) - val profile = profileFunction.getProfile() - private val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 + val autoIsfWeights; get() = preferences.get(BooleanKey.ApsUseAutoIsfWeights) + private val autoISF_max; get() = preferences.get(DoubleKey.ApsAutoIsfMax) + private val autoISF_min; get() = preferences.get(DoubleKey.ApsAutoIsfMin) + private val bgAccel_ISF_weight; get() = preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight) + private val bgBrake_ISF_weight; get() = preferences.get(DoubleKey.ApsAutoIsfBgBrakeWeight) + private val enable_pp_ISF_always; get() = preferences.get(BooleanKey.ApsAutoIsfPpAlways) + private val pp_ISF_hours; get() = preferences.get(IntKey.ApsAutoIsfPpIsfHours) + private val pp_ISF_weight; get() = preferences.get(DoubleKey.ApsAutoIsfPpWeight) + private val delta_ISFrange_weight; get() = preferences.get(DoubleKey.ApsAutoIsfDeltaWeight) + private val lower_ISFrange_weight; get() = preferences.get(DoubleKey.ApsAutoIsfLowBgWeight) + private val higher_ISFrange_weight; get() = preferences.get(DoubleKey.ApsAutoIsfHighBgWeight) + private val enable_dura_ISF_with_COB; get() = preferences.get(BooleanKey.ApsAutoIsfDuraAfterCarbs) + private val dura_ISF_weight; get() = preferences.get(DoubleKey.ApsAutoIsfDuraWeight) + private val smb_delivery_ratio; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) + private val smb_delivery_ratio_min; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) + private val smb_delivery_ratio_max; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) + private val smb_delivery_ratio_bg_range; get() = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) + val smbMaxRangeExtension; get() = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + private val enableSMB_EvenOn_OddOff; get() = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt) // for TT + private val enableSMB_EvenOn_OddOff_always; get() = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt) // for profile target + val iobThresholdPercent; get() = preferences.get(IntKey.ApsAutoIsfIobThPercent) + private val exerciseMode; get() = SMBDefaults.exercise_mode + private val highTemptargetRaisesSensitivity; get() = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) + // val profile = profileFunction.getProfile() + // private val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 val normalTarget = 100 override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) @@ -252,7 +252,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // End of check, start gathering data - val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) + val autoIsfMode = true // preferences.get(BooleanKey.ApsUseAutoIsf) val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() @@ -366,7 +366,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } var iobTH_reduction_ratio = 1.0 var use_iobTH = false - val iobThresholdPercent = preferences.get(IntKey.ApsAutoIsfIobThPercent) // make it dynamic? if (iobThresholdPercent != 100) { iobTH_reduction_ratio = profile_percentage / 100.0 * exerciseRatio use_iobTH = true @@ -414,7 +413,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") aapsLogger.debug(LTag.APS, "AutoIsfMode: $autoIsfMode") - aapsLogger.debug(LTag.APS, "AutoISF extras: {"+autoIsfExtras+"}") + aapsLogger.debug(LTag.APS, "AutoISF extras: {$autoIsfExtras}") determineBasalAutoISF.determine_basal( glucose_status = glucoseStatus, @@ -533,10 +532,10 @@ open class OpenAPSAutoISFPlugin @Inject constructor( fun autoISF(currentTime: Long, profile: Profile): Double { val sens = profile.getProfileIsfMgdl() val glucose_status = glucoseStatusProvider.glucoseStatusData - val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) + // val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) - if (!autoIsfMode || !autoIsfWeights || glucose_status == null) { - consoleError.add("autoISF disabled in Preferences") + if (!autoIsfWeights || glucose_status == null) { + consoleError.add("autoISF weights disabled in Preferences") consoleError.add("----------------------------------") consoleError.add("end AutoISF") consoleError.add("----------------------------------") @@ -570,7 +569,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // limit sensitivityRatio to profile.autosens_max (1.2x by default) sensitivityRatio = min(sensitivityRatio, preferences.get(DoubleKey.AutosensMax)) sensitivityRatio = round(sensitivityRatio, 2) - origin_sens = " from TT modifier" + origin_sens = " from low TT modifier" // consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") } } else { @@ -604,11 +603,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( var delta_ISF = 1.0 var acce_ISF = 1.0 var acce_weight = 1.0 - val bg_off = target_bg + 10.0 - glucose_status.glucose; // move from central BG=100 to target+10 as virtual BG'=100 + val bg_off = target_bg + 10.0 - glucose_status.glucose // move from central BG=100 to target+10 as virtual BG'=100 // calculate acce_ISF from bg acceleration and adapt ISF accordingly val fit_corr: Double = glucose_status.corrSqu val bg_acce: Double = glucose_status.bgAcceleration + consoleError.add("Parabola fit results were acceleration:${round(bg_acce,2)}, correlation:$fit_corr, duration:${glucose_status.parabolaMinutes}m") if (glucose_status.a2 != 0.0 && fit_corr >= 0.9) { var minmax_delta: Double = -glucose_status.a1 / 2 / glucose_status.a2 * 5 // back from 5min block to 1 min var minmax_value: Double = round(glucose_status.a0 - minmax_delta * minmax_delta / 25 * glucose_status.a2, 1) @@ -691,7 +691,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } else -> { - delta_ISF = interpolate(bg_delta, "delta"); + delta_ISF = interpolate(bg_delta, "delta") // mod V14d: halve the effect below target_bg+30 if (bg_off > -20.0) { delta_ISF = 0.5 * delta_ISF @@ -712,7 +712,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB, 1)}") } dura05 < 10.0 -> { - consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05"); + consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05") } avg05 <= target_bg -> { consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") @@ -832,16 +832,18 @@ open class OpenAPSAutoISFPlugin @Inject constructor( liftISFlimited = maxISFReduction } val finalISF: Double - var origin_sens_final = origin_sens + var originSensFinal = origin_sens if (high_temptarget_raises_sensitivity && temptargetSet && target_bg > normalTarget) { finalISF = liftISFlimited * sensitivityRatio - origin_sens_final = " including exercise mode impact" + originSensFinal = " including exercise mode impact" } else if (liftISFlimited >= 1) { finalISF = max(liftISFlimited, sensitivityRatio) + if (liftISFlimited >= sensitivityRatio) originSensFinal = "" // autoISF dominates } else { finalISF = min(liftISFlimited, sensitivityRatio) + if (liftISFlimited <= sensitivityRatio) originSensFinal = "" // autoISF dominates } - consoleError.add("final ISF factor is ${round(finalISF, 2)}" + origin_sens_final) + consoleError.add("final ISF factor is ${round(finalISF, 2)}" + originSensFinal) consoleError.add("----------------------------------") consoleError.add("end AutoISF") consoleError.add("----------------------------------") @@ -867,17 +869,17 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } if (profile.out_units == "mmol/L") { evenTarget = (target.toDouble() * 10.0).toInt() % 2 == 0 - msgUnits = "has " + msgUnits = "has" msgTail = "decimal" } else { evenTarget = target.toInt() % 2 == 0 - msgUnits = "is " + msgUnits = "is" msgTail = "number" } msgEven = if (evenTarget) { - "even " + "even" } else { - "odd " + "odd" } val iobThUser = preferences.get(IntKey.ApsAutoIsfIobThPercent) //iobThresholdPercent @@ -939,7 +941,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( new_SMB = lower_SMB + (higher_SMB - lower_SMB) * (bg - target_bg) / smb_delivery_ratio_bg_range new_SMB = max(lower_SMB, min(higher_SMB, new_SMB)) // cap if outside target_bg--higher_bg } - if (loop_wanted_smb == "fullLoop") { // go for max impactError.add("SMB delivery ratio set to ${max(fix_SMB, new_SMB)} as max of fixed and interpolated values") + if (loop_wanted_smb == "fullLoop") { // go for max impact + consoleError.add("SMB delivery ratio set to ${max(fix_SMB, new_SMB)} as max of fixed and interpolated values") return max(fix_SMB, new_SMB) } @@ -1021,7 +1024,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( ) ) }) - addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsf, summary = R.string.use_autoISF_extensions_summary, title = R.string.use_autoISF_extensions_title)) + // addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutoIsf, summary = R.string.use_autoISF_extensions_summary, title = R.string.use_autoISF_extensions_title)) addPreference(preferenceManager.createPreferenceScreen(context).apply { key = "auto_isf_settings" title = rh.gs(R.string.autoISF_settings_title) From 0cbc5b9e79a085aa16da72c99ec2f95dd92456ae Mon Sep 17 00:00:00 2001 From: Philoul Date: Thu, 18 Apr 2024 17:37:54 +0200 Subject: [PATCH 27/38] AutoISF Code Cleaning --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 8 +- .../core/interfaces/aps/AutoISFProfile.kt | 76 --------- .../aaps/core/interfaces/aps/OapsProfile.kt | 24 ++- .../core/objects/aps/DetermineBasalResult.kt | 2 - .../openAPSAutoISF/DetermineBasalAutoISF.kt | 6 +- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 145 ++++++++---------- .../OpenAPSAutoISFPluginTest.kt | 2 +- 7 files changed, 96 insertions(+), 167 deletions(-) delete mode 100644 core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 0fb1e5dfb11..235938bd06c 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -10,7 +10,6 @@ import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile -import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.maintenance.FileListProvider @@ -712,7 +711,7 @@ class ReplayApsResultsTest @Inject constructor() { insulinDivisor = 0, TDD = 0.0 ) - val profile = AutoISFProfile( + val profile = OapsProfile( dia = 0.0, min_5m_carbimpact = 0.0, max_iob = determineBasalResult.profile.getDouble("max_iob"), @@ -753,6 +752,9 @@ class ReplayApsResultsTest @Inject constructor() { temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), autosens_max = determineBasalResult.profile.getDouble("autosens_max"), out_units = determineBasalResult.profile.optString("out_units"), + variable_sens = determineBasalResult.profile.getDouble("variable_sens"), + insulinDivisor = 0, + TDD = 0.0, autoISF_version = determineBasalResult.profile.optString("autoISF_version"), enable_autoISF = determineBasalResult.profile.getBoolean("enable_autoISF"), autoISF_max = determineBasalResult.profile.getDouble("autoISF_max"), @@ -763,8 +765,6 @@ class ReplayApsResultsTest @Inject constructor() { pp_ISF_hours = determineBasalResult.profile.getInt("pp_ISF_hours"), pp_ISF_weight = determineBasalResult.profile.getDouble("pp_ISF_weight"), delta_ISFrange_weight = determineBasalResult.profile.getDouble("delta_ISFrange_weight"), - lower_ISFrange_weight = determineBasalResult.profile.getDouble("lower_ISFrange_weight"), - higher_ISFrange_weight = determineBasalResult.profile.getDouble("higher_ISFrange_weight"), enable_dura_ISF_with_COB = determineBasalResult.profile.getBoolean("enable_dura_ISF_with_COB"), dura_ISF_weight = determineBasalResult.profile.getDouble("dura_ISF_weight"), smb_delivery_ratio = determineBasalResult.profile.getDouble("smb_delivery_ratio"), diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt deleted file mode 100644 index 0e2f9fc1d6c..00000000000 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/AutoISFProfile.kt +++ /dev/null @@ -1,76 +0,0 @@ -package app.aaps.core.interfaces.aps - -import kotlinx.serialization.Serializable - -@Serializable -data class AutoISFProfile( - var dia: Double, // AMA only - var min_5m_carbimpact: Double, // AMA only - var max_iob: Double, - var max_daily_basal: Double, - var max_basal: Double, - var min_bg: Double, - var max_bg: Double, - var target_bg: Double, - var carb_ratio: Double, - var sens: Double, - var autosens_adjust_targets: Boolean, // AMA only - var max_daily_safety_multiplier: Double, - var current_basal_safety_multiplier: Double, - var high_temptarget_raises_sensitivity: Boolean, - var low_temptarget_lowers_sensitivity: Boolean, - var sensitivity_raises_target: Boolean, - var resistance_lowers_target: Boolean, - var adv_target_adjustments: Boolean, - var exercise_mode: Boolean, - var half_basal_exercise_target: Int, - var maxCOB: Int, - var skip_neutral_temps: Boolean, - var remainingCarbsCap: Int, - var enableUAM: Boolean, - var A52_risk_enable: Boolean, - var SMBInterval: Int, - var enableSMB_with_COB: Boolean, - var enableSMB_with_temptarget: Boolean, - var allowSMB_with_high_temptarget: Boolean, - var enableSMB_always: Boolean, - var enableSMB_after_carbs: Boolean, - var maxSMBBasalMinutes: Int, - var maxUAMSMBBasalMinutes: Int, - var bolus_increment: Double, - var carbsReqThreshold: Int, - var current_basal: Double, - var temptargetSet: Boolean, - var autosens_max: Double, - var out_units: String, - var lgsThreshold: Int?, - //DynISF only - //var variable_sens: Double, - //var insulinDivisor: Int, - //var TDD: Double, - //AutoISF only - var autoISF_version: String, - var enable_autoISF: Boolean, - var autoISF_max: Double, - var autoISF_min: Double, - var bgAccel_ISF_weight: Double, - var bgBrake_ISF_weight: Double, - var enable_pp_ISF_always: Boolean, - var pp_ISF_hours: Int, - var pp_ISF_weight: Double, - var delta_ISFrange_weight: Double, - var lower_ISFrange_weight: Double, - var higher_ISFrange_weight: Double, - var enable_dura_ISF_with_COB: Boolean, - var dura_ISF_weight: Double, - var smb_delivery_ratio: Double, - var smb_delivery_ratio_min: Double, - var smb_delivery_ratio_max: Double, - var smb_delivery_ratio_bg_range: Double, - var smb_max_range_extension: Double, - var enableSMB_EvenOn_OddOff: Boolean, - var enableSMB_EvenOn_OddOff_always: Boolean, - var iob_threshold_percent: Int, - var profile_percentage: Int - -) \ No newline at end of file diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt index 5dbbe01c4eb..0898e214b00 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt @@ -47,5 +47,27 @@ data class OapsProfile( //DynISF only var variable_sens: Double, var insulinDivisor: Int, - var TDD: Double + var TDD: Double, + //AutoISF only + var autoISF_version: String = "", + var enable_autoISF: Boolean = true, + var autoISF_max: Double = 1.0, + var autoISF_min: Double = 1.0, + var bgAccel_ISF_weight: Double = 0.0, + var bgBrake_ISF_weight: Double = 0.0, + var enable_pp_ISF_always: Boolean = false, + var pp_ISF_hours: Int = 3, + var pp_ISF_weight: Double = 0.0, + var delta_ISFrange_weight: Double = 0.0, + var enable_dura_ISF_with_COB: Boolean = false, + var dura_ISF_weight: Double = 0.0, + var smb_delivery_ratio: Double = 0.5, + var smb_delivery_ratio_min: Double = 0.5, + var smb_delivery_ratio_max: Double = 0.5, + var smb_delivery_ratio_bg_range: Double = 0.0, + var smb_max_range_extension: Double = 1.0, + var enableSMB_EvenOn_OddOff: Boolean = false, + var enableSMB_EvenOn_OddOff_always: Boolean = false, + var iob_threshold_percent: Int = 100, + var profile_percentage: Int = 100 ) \ No newline at end of file diff --git a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt index a04b6192fe0..58ac79fd5af 100644 --- a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt +++ b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt @@ -12,7 +12,6 @@ import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile -import app.aaps.core.interfaces.aps.AutoISFProfile import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.constraints.Constraint @@ -80,7 +79,6 @@ class DetermineBasalResult @Inject constructor(val injector: HasAndroidInjector) override var glucoseStatus: GlucoseStatus? = null override var currentTemp: CurrentTemp? = null override var oapsProfile: OapsProfile? = null - var autoIsfProfile: AutoISFProfile? = null override var mealData: MealData? = null lateinit var result: RT diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 3f86d0b8bcd..7884b85752d 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -156,7 +156,7 @@ class DetermineBasalAutoISF @Inject constructor( consoleLog.clear() var rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = false, // autoIsfMode, + runningDynamicIsf = autoIsfMode, timestamp = currentTime, consoleLog = consoleLog, consoleError = consoleError @@ -311,7 +311,7 @@ class DetermineBasalAutoISF @Inject constructor( if (autoIsfMode) { consoleError.add("----------------------------------") - consoleError.add("start AutoISF 3.0") + consoleError.add("start AutoISF ${profile.autoISF_version}") consoleError.add("----------------------------------") consoleError.addAll(auto_isf_console) } @@ -404,7 +404,7 @@ class DetermineBasalAutoISF @Inject constructor( rT = RT( algorithm = APSResult.Algorithm.AUTO_ISF, - runningDynamicIsf = false, // autoIsfMode, + runningDynamicIsf = autoIsfMode, timestamp = currentTime, bg = bg, tick = tick, diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 8bb088c7472..f9d80325482 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -69,6 +69,7 @@ import app.aaps.plugins.aps.R import app.aaps.plugins.aps.events.EventOpenAPSUpdateGui import app.aaps.plugins.aps.events.EventResetOpenAPSGui import dagger.android.HasAndroidInjector +import kotlinx.serialization.json.Json import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton @@ -118,7 +119,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( override val algorithm = APSResult.Algorithm.AUTO_ISF override var lastAPSResult: DetermineBasalResult? = null private var consoleError = mutableListOf() - + val autoIsfVersion = "3.0" val autoIsfWeights; get() = preferences.get(BooleanKey.ApsUseAutoIsfWeights) private val autoISF_max; get() = preferences.get(DoubleKey.ApsAutoIsfMax) private val autoISF_min; get() = preferences.get(DoubleKey.ApsAutoIsfMin) @@ -142,11 +143,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobThresholdPercent; get() = preferences.get(IntKey.ApsAutoIsfIobThPercent) private val exerciseMode; get() = SMBDefaults.exercise_mode private val highTemptargetRaisesSensitivity; get() = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens) - // val profile = profileFunction.getProfile() - // private val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 val normalTarget = 100 - override fun supportsDynamicIsf(): Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) + override fun supportsDynamicIsf() = true //: Boolean = preferences.get(BooleanKey.ApsUseAutoIsf) override fun getIsfMgdl(multiplier: Double, timeShift: Int, caller: String): Double? { val start = dateUtil.now() @@ -187,7 +186,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val dynIsfCache = LongSparseArray() private fun calculateVariableIsf(timestamp: Long, bg: Double?): Pair { - // Todo : Calculate here ISF value with AutoISF algo val profile = profileFunction.getProfile(timestamp) if (profile == null) return Pair("OFF", null) if (!preferences.get(BooleanKey.ApsUseDynamicSensitivity)) return Pair("OFF", null) @@ -208,7 +206,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // no cached result found, let's calculate the value val autoIsfTimestamp = autoISF(timestamp, profile) val sensitivity = autoIsfTimestamp - //aapsLogger.debug("XXXXX ${dateUtil.dateAndTimeAndSecondsString(timestamp)} ${profile.getProfileIsfMgdl()} -> ${autoIsfTimestamp}") dynIsfCache.put(key, sensitivity) if (dynIsfCache.size() > 1000) dynIsfCache.clear() return Pair("CALC", sensitivity) @@ -252,7 +249,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // End of check, start gathering data - val autoIsfMode = true // preferences.get(BooleanKey.ApsUseAutoIsf) + val autoIsfMode = supportsDynamicIsf() // preferences.get(BooleanKey.ApsUseAutoIsf) val smbEnabled = preferences.get(BooleanKey.ApsUseSmb) val advancedFiltering = constraintsChecker.isAdvancedFilteringEnabled().also { inputConstraints.copyReasons(it) }.value() @@ -286,7 +283,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } autosensResult = autosensData.autosensResult } else autosensResult.sensResult = "autosens disabled" - val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), isTempTarget) + val iobArray = iobCobCalculator.calculateIobArrayForSMB(autosensResult, SMBDefaults.exercise_mode, preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), isTempTarget) val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() val iobData = iobArray[0] val profile_percentage = if (profile is ProfileSealed.EPS) profile.value.originalPercentage else 100 @@ -337,31 +334,49 @@ open class OpenAPSAutoISFPlugin @Inject constructor( temptargetSet = isTempTarget, autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", - variable_sens = variableSensitivity, //variableSensitivity, + variable_sens = variableSensitivity, insulinDivisor = 0, - TDD = 0.0 + TDD = 0.0, + autoISF_version = autoIsfVersion, + enable_autoISF = autoIsfWeights, + autoISF_max = autoISF_max, + autoISF_min = autoISF_min, + bgAccel_ISF_weight = bgAccel_ISF_weight, + bgBrake_ISF_weight = bgBrake_ISF_weight, + enable_pp_ISF_always = enable_pp_ISF_always, + pp_ISF_hours = pp_ISF_hours, + pp_ISF_weight = pp_ISF_weight, + delta_ISFrange_weight = delta_ISFrange_weight, + enable_dura_ISF_with_COB = enable_dura_ISF_with_COB, + dura_ISF_weight = dura_ISF_weight, + smb_delivery_ratio = smb_delivery_ratio, + smb_delivery_ratio_min = smb_delivery_ratio_min, + smb_delivery_ratio_max = smb_delivery_ratio_max, + smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range, + smb_max_range_extension = smbMaxRangeExtension, + enableSMB_EvenOn_OddOff = enableSMB_EvenOn_OddOff, + enableSMB_EvenOn_OddOff_always = enableSMB_EvenOn_OddOff_always, + iob_threshold_percent = iobThresholdPercent, + profile_percentage = profile_percentage ) //done calculate exercise ratio var exerciseRatio = 1.0 - var sensitivityRatio = 1.0 + // TODO eliminate var origin_sens = "" val target_bg = (minBg + maxBg) / 2 if (highTemptargetRaisesSensitivity && isTempTarget && target_bg > normalTarget - || oapsProfile.low_temptarget_lowers_sensitivity && isTempTarget && target_bg < normalTarget ) { + || oapsProfile.low_temptarget_lowers_sensitivity && isTempTarget && target_bg < normalTarget + ) { // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); val c = (oapsProfile.half_basal_exercise_target - normalTarget).toDouble() - if (c * (c + target_bg-normalTarget) <= 0.0) { - sensitivityRatio = oapsProfile.autosens_max - } else { - sensitivityRatio = c / (c + target_bg - normalTarget) + if (c * (c + target_bg - normalTarget) > 0.0) { + var sensitivityRatio = c / (c + target_bg - normalTarget) // limit sensitivityRatio to profile.autosens_max (1.2x by default) sensitivityRatio = min(sensitivityRatio, preferences.get(DoubleKey.AutosensMax)) sensitivityRatio = round(sensitivityRatio, 2) exerciseRatio = sensitivityRatio - origin_sens = "from TT modifier" - //consoleError.add("Sensitivity ratio set to $sensitivityRatio based on temp target of $target_bg; ") } } var iobTH_reduction_ratio = 1.0 @@ -370,39 +385,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( iobTH_reduction_ratio = profile_percentage / 100.0 * exerciseRatio use_iobTH = true } - // mod autoISF3.0-dev: if that would put us over iobTH, then reduce accordingly; allow 30% overrun val iobTHtolerance = 130.0 - val iobTHvirtual = iobThresholdPercent*iobTHtolerance/10000.0 * oapsProfile.max_iob * iobTH_reduction_ratio - val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, use_iobTH, iobTHvirtual/iobTHtolerance*100.0) - //if (autoIsfMode) - // microBolusAllowed = microBolusAllowed && loopWantedSmb != "AAPS" && (loopWantedSmb == "enforced" || loopWantedSmb == "fullLoop") + val iobTHvirtual = iobThresholdPercent * iobTHtolerance / 10000.0 * oapsProfile.max_iob * iobTH_reduction_ratio + val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, use_iobTH, iobTHvirtual / iobTHtolerance * 100.0) val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT val smbRatio = determine_varSMBratio(oapsProfile, glucoseStatus.glucose.toInt(), target_bg, loopWantedSmb) - var autoIsfExtras = """"low_temptarget_lowers_sensitivity":${preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens)}""" - autoIsfExtras += """, "enable_autoISF":$autoIsfWeights""" - autoIsfExtras += """, "autoISF_max":$autoISF_max""" - autoIsfExtras += """, "autoISF_min":$autoISF_min""" - autoIsfExtras += """, "bgAccel_ISF_weight":$bgAccel_ISF_weight""" - autoIsfExtras += """, "bgBrake_ISF_weight":$bgBrake_ISF_weight""" - autoIsfExtras += """, "enable_pp_ISF_always":$enable_pp_ISF_always""" - autoIsfExtras += """, "pp_ISF_hours":$pp_ISF_hours""" - autoIsfExtras += """, "pp_ISF_weight":$pp_ISF_weight""" - autoIsfExtras += """, "delta_ISFrange_weight":$delta_ISFrange_weight""" - autoIsfExtras += """, "lower_ISFrange_weight":$lower_ISFrange_weight""" - autoIsfExtras += """, "higher_ISFrange_weight":$higher_ISFrange_weight""" - autoIsfExtras += """, "enable_dura_ISF_with_COB":$enable_dura_ISF_with_COB""" - autoIsfExtras += """, "dura_ISF_weight":$dura_ISF_weight""" - autoIsfExtras += """, "smb_delivery_ratio":$smb_delivery_ratio""" - autoIsfExtras += """, "smb_delivery_ratio_min":$smb_delivery_ratio_min""" - autoIsfExtras += """, "smb_delivery_ratio_max":$smb_delivery_ratio_max""" - autoIsfExtras += """, "smb_delivery_ratio_bg_range":$smb_delivery_ratio_bg_range""" - autoIsfExtras += """, "smb_max_range_extension":$smbMaxRangeExtension""" - autoIsfExtras += """, "enableSMB_EvenOn_OddOff":$enableSMB_EvenOn_OddOff""" - autoIsfExtras += """, "enableSMB_EvenOn_OddOff_always":$enableSMB_EvenOn_OddOff_always""" - autoIsfExtras += """, "iob_threshold_percent":$iobThresholdPercent""" - autoIsfExtras += """, "profile_percentage":$profile_percentage""" - aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AutoISF <<<") aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") aapsLogger.debug(LTag.APS, "Current temp: $currentTemp") @@ -413,7 +401,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") aapsLogger.debug(LTag.APS, "AutoIsfMode: $autoIsfMode") - aapsLogger.debug(LTag.APS, "AutoISF extras: {$autoIsfExtras}") + aapsLogger.debug(LTag.APS, "AutoISF extras: ${Json.encodeToString(OapsProfile.serializer(), oapsProfile)}") determineBasalAutoISF.determine_basal( glucose_status = glucoseStatus, @@ -431,7 +419,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( smb_ratio = smbRatio, smb_max_range_extension = smbMaxRangeExtension, iob_threshold_percent = iobThresholdPercent, - auto_isf_console = consoleError + auto_isf_console = consoleError ).also { val determineBasalResult = DetermineBasalResult(injector, it) // Preserve input data @@ -534,7 +522,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val glucose_status = glucoseStatusProvider.glucoseStatusData // val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) - if (!autoIsfWeights || glucose_status == null) { + if (!supportsDynamicIsf() || !autoIsfWeights || glucose_status == null) { consoleError.add("autoISF weights disabled in Preferences") consoleError.add("----------------------------------") consoleError.add("end AutoISF") @@ -560,7 +548,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); val halfBasalTarget = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget) val c = (halfBasalTarget - normalTarget).toDouble() - if (c * (c + target_bg-normalTarget) <= 0.0) { + if (c * (c + target_bg - normalTarget) <= 0.0) { sensitivityRatio = preferences.get(DoubleKey.AutosensMax) // consoleError.add("Sensitivity decrease for temp target of $target_bg limited by Autosens_max; ") @@ -583,7 +571,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( sensitivityRatio = autosensResult.ratio // consoleError.add("Autosens ratio: $sensitivityRatio; ") } - // Todo include here exercise_ratio calculation val autosensResult = AutosensResult() if (constraintsChecker.isAutosensModeEnabled().value()) { @@ -608,7 +595,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( // calculate acce_ISF from bg acceleration and adapt ISF accordingly val fit_corr: Double = glucose_status.corrSqu val bg_acce: Double = glucose_status.bgAcceleration - consoleError.add("Parabola fit results were acceleration:${round(bg_acce,2)}, correlation:$fit_corr, duration:${glucose_status.parabolaMinutes}m") + consoleError.add("Parabola fit results were acceleration:${round(bg_acce, 2)}, correlation:$fit_corr, duration:${glucose_status.parabolaMinutes}m") if (glucose_status.a2 != 0.0 && fit_corr >= 0.9) { var minmax_delta: Double = -glucose_status.a1 / 2 / glucose_status.a2 * 5 // back from 5min block to 1 min var minmax_value: Double = round(glucose_status.a0 - minmax_delta * minmax_delta / 25 * glucose_status.a2, 1) @@ -627,9 +614,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( if (fit_corr < 0.9) { consoleError.add("acce_ISF adaptation by-passed as correlation ${round(fit_corr, 3)} is too low") } else { - val fit_share = 10 * (fit_corr - 0.9) // 0 at correlation 0.9, 1 at 1.00 + val fit_share = 10 * (fit_corr - 0.9) // 0 at correlation 0.9, 1 at 1.00 var cap_weight = 1.0 // full contribution above target - if (acce_weight == 1.0 && glucose_status.glucose < target_bg) { // below target acce goes towards target + if (acce_weight == 1.0 && glucose_status.glucose < target_bg) { // below target acce goes towards target if (bg_acce > 0) { if (bg_acce > 1) { cap_weight = 0.5 @@ -679,9 +666,11 @@ open class OpenAPSAutoISFPlugin @Inject constructor( bg_off > 0.0 -> { consoleError.add(deltaType + "_ISF adaptation by-passed as average glucose < $target_bg+10") } + glucose_status.shortAvgDelta < 0 -> { consoleError.add(deltaType + "_ISF adaptation by-passed as no rise or too short lived") } + deltaType == "pp" -> { pp_ISF = 1.0 + max(0.0, bg_delta * pp_ISF_weight) consoleError.add("pp_ISF adaptation is ${round(pp_ISF, 2)}") @@ -690,6 +679,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } } + else -> { delta_ISF = interpolate(bg_delta, "delta") // mod V14d: halve the effect below target_bg+30 @@ -711,12 +701,15 @@ open class OpenAPSAutoISFPlugin @Inject constructor( meal_data.mealCOB > 0 && !enable_dura_ISF_with_COB -> { consoleError.add("dura_ISF by-passed; preferences disabled mealCOB of ${round(meal_data.mealCOB, 1)}") } - dura05 < 10.0 -> { + + dura05 < 10.0 -> { consoleError.add("dura_ISF by-passed; bg is only $dura05 m at level $avg05") } - avg05 <= target_bg -> { + + avg05 <= target_bg -> { consoleError.add("dura_ISF by-passed; avg. glucose $avg05 below target $target_bg") } + else -> { // fight the resistance at high levels val dura05Weight = dura05 / 60 @@ -838,10 +831,10 @@ open class OpenAPSAutoISFPlugin @Inject constructor( originSensFinal = " including exercise mode impact" } else if (liftISFlimited >= 1) { finalISF = max(liftISFlimited, sensitivityRatio) - if (liftISFlimited >= sensitivityRatio) originSensFinal = "" // autoISF dominates + if (liftISFlimited >= sensitivityRatio) originSensFinal = "" // autoISF dominates } else { finalISF = min(liftISFlimited, sensitivityRatio) - if (liftISFlimited <= sensitivityRatio) originSensFinal = "" // autoISF dominates + if (liftISFlimited <= sensitivityRatio) originSensFinal = "" // autoISF dominates } consoleError.add("final ISF factor is ${round(finalISF, 2)}" + originSensFinal) consoleError.add("----------------------------------") @@ -883,12 +876,12 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } val iobThUser = preferences.get(IntKey.ApsAutoIsfIobThPercent) //iobThresholdPercent - if ( useIobTh ) { - val iobThPercent = round(iobThEffective/profile.max_iob*100.0, 0) - if ( iobThPercent == iobThUser.toDouble() ) { + if (useIobTh) { + val iobThPercent = round(iobThEffective / profile.max_iob * 100.0, 0) + if (iobThPercent == iobThUser.toDouble()) { consoleError.add("User setting iobTH=$iobThUser% not modulated") } else { - consoleError.add("User setting iobTH=$iobThUser% modulated to ${iobThPercent.toInt()}% or ${round(iobThEffective,2)}U") + consoleError.add("User setting iobTH=$iobThUser% modulated to ${iobThPercent.toInt()}% or ${round(iobThEffective, 2)}U") consoleError.add(" due to profile %, exercise mode or similar") } } else { @@ -902,24 +895,18 @@ open class OpenAPSAutoISFPlugin @Inject constructor( } else if (profile.max_iob == 0.0) { consoleError.add("SMB disabled because of max_iob=0") return "blocked" - } else if ( useIobTh && iobThEffective < iob_data_iob ) { - //if (iobTH_reduction_ratio != 1.0) { - // consoleError.add("Full Loop modified max_iob ${profile.max_iob} to effectively ${round(profile.max_iob * iobTH_reduction_ratio, 2)} due to profile % and/or exercise mode") - // msg = "effective maxIOB ${round(profile.max_iob * iobTH_reduction_ratio, 2)}" - //} else { - // msg = "maxIOB ${profile.max_iob}" - //} + } else if (useIobTh && iobThEffective < iob_data_iob) { consoleError.add("SMB disabled by Full Loop logic: iob ${iob_data_iob} is above effective iobTH $iobThEffective") consoleError.add("Full Loop capped") return "iobTH" } else { consoleError.add("SMB enabled; $msgType $target $msgUnits $msgEven $msgTail") - if (profile.target_bg < 100) { // indirect assessment; later set it in GUI + return if (profile.target_bg < 100) { // indirect assessment; later set it in GUI consoleError.add("Loop allows full power") - return "fullLoop" // even number + "fullLoop" // even number } else { consoleError.add("Loop allows medium power") - return "enforced" // even number + "enforced" // even number } } } @@ -932,10 +919,10 @@ open class OpenAPSAutoISFPlugin @Inject constructor( if (smb_delivery_ratio_bg_range < 10) { smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 } // was in mmol/l - var fix_SMB: Double = smb_delivery_ratio - var lower_SMB = min(smb_delivery_ratio_min, smb_delivery_ratio_max) - var higher_SMB = max(smb_delivery_ratio_min, smb_delivery_ratio_max) - var higher_bg = target_bg + smb_delivery_ratio_bg_range + val fix_SMB: Double = smb_delivery_ratio + val lower_SMB = min(smb_delivery_ratio_min, smb_delivery_ratio_max) + val higher_SMB = max(smb_delivery_ratio_min, smb_delivery_ratio_max) + val higher_bg = target_bg + smb_delivery_ratio_bg_range var new_SMB: Double = fix_SMB if (smb_delivery_ratio_bg_range > 0) { new_SMB = lower_SMB + (higher_SMB - lower_SMB) * (bg - target_bg) / smb_delivery_ratio_bg_range @@ -973,7 +960,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( requiredKey != "dura_ISF_settings" && requiredKey != "smb_delivery_settings" && requiredKey != "full_loop_settings" - ) return + ) return val category = PreferenceCategory(context) parent.addPreference(category) category.apply { @@ -983,9 +970,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsMaxBasal, dialogMessage = R.string.openapsma_max_basal_summary, title = R.string.openapsma_max_basal_title)) addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsSmbMaxIob, dialogMessage = R.string.openapssmb_max_iob_summary, title = R.string.openapssmb_max_iob_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutosens, title = R.string.openapsama_use_autosens)) - //addPreference(AdaptiveIntPreference(ctx = context, intKey = IntKey.ApsDynIsfAdjustmentFactor, dialogMessage = R.string.dyn_isf_adjust_summary, title = R.string.dyn_isf_adjust_title)) addPreference(AdaptiveUnitPreference(ctx = context, unitKey = UnitDoubleKey.ApsLgsThreshold, dialogMessage = R.string.lgs_threshold_summary, title = R.string.lgs_threshold_title)) - //addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsDynIsfAdjustSensitivity, summary = R.string.dynisf_adjust_sensitivity_summary, title = R.string.dynisf_adjust_sensitivity)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsSensitivityRaisesTarget, summary = R.string.sensitivity_raises_target_summary, title = R.string.sensitivity_raises_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsResistanceLowersTarget, summary = R.string.resistance_lowers_target_summary, title = R.string.resistance_lowers_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfHighTtRaisesSens, summary = R.string.high_temptarget_raises_sensitivity_summary, title = R.string.high_temptarget_raises_sensitivity_title)) diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index 65ba04c6927..b9312ffb6f1 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -165,7 +165,7 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = 100.0, //variableSensitivity, insulinDivisor = 0, - TDD = 0.0 + TDD = 0.0 // TODO complete with AutoISF dedicated parameters ) assertThat(openAPSAutoISFPlugin.determine_varSMBratio(oapsProfile,100, 90.0, "fullLoop")).isEqualTo(0.5) } From d4f59c1b7edaab5febec51f887b124a52e4fe7cf Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Mon, 22 Apr 2024 14:32:43 +0200 Subject: [PATCH 28/38] fix exercise mode, prepare unit tests --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 63 +++---------------- .../aaps/core/interfaces/aps/OapsProfile.kt | 2 + .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 22 ++++--- .../OpenAPSAutoISFPluginTest.kt | 18 ++++-- 4 files changed, 36 insertions(+), 69 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 235938bd06c..46e397afddb 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -666,51 +666,6 @@ class ReplayApsResultsTest @Inject constructor() { for (i in 0 until determineBasalResult.iobData!!.length()) iobData.add(determineBasalResult.iobData!!.getJSONObject(i).toIob()) val currentTime = determineBasalResult.currentTime - val oprofile = OapsProfile( - dia = 0.0, - min_5m_carbimpact = 0.0, - max_iob = determineBasalResult.profile.getDouble("max_iob"), - max_daily_basal = determineBasalResult.profile.getDouble("max_daily_basal"), - max_basal = determineBasalResult.profile.getDouble("max_basal"), - min_bg = determineBasalResult.profile.getDouble("min_bg"), - max_bg = determineBasalResult.profile.getDouble("max_bg"), - target_bg = determineBasalResult.profile.getDouble("target_bg"), - carb_ratio = determineBasalResult.profile.getDouble("carb_ratio"), - sens = determineBasalResult.profile.getDouble("sens"), - autosens_adjust_targets = false, - max_daily_safety_multiplier = determineBasalResult.profile.getDouble("max_daily_safety_multiplier"), - current_basal_safety_multiplier = determineBasalResult.profile.getDouble("current_basal_safety_multiplier"), - lgsThreshold = null, - high_temptarget_raises_sensitivity = determineBasalResult.profile.getBoolean("high_temptarget_raises_sensitivity"), - low_temptarget_lowers_sensitivity = determineBasalResult.profile.getBoolean("low_temptarget_lowers_sensitivity"), - sensitivity_raises_target = determineBasalResult.profile.getBoolean("sensitivity_raises_target"), - resistance_lowers_target = determineBasalResult.profile.getBoolean("resistance_lowers_target"), - adv_target_adjustments = determineBasalResult.profile.getBoolean("adv_target_adjustments"), - exercise_mode = determineBasalResult.profile.getBoolean("exercise_mode"), - half_basal_exercise_target = determineBasalResult.profile.getInt("half_basal_exercise_target"), - maxCOB = determineBasalResult.profile.getInt("maxCOB"), - skip_neutral_temps = determineBasalResult.profile.getBoolean("skip_neutral_temps"), - remainingCarbsCap = determineBasalResult.profile.getInt("remainingCarbsCap"), - enableUAM = determineBasalResult.profile.getBoolean("enableUAM"), - A52_risk_enable = determineBasalResult.profile.getBoolean("A52_risk_enable"), - SMBInterval = determineBasalResult.profile.getInt("SMBInterval"), - enableSMB_with_COB = determineBasalResult.profile.getBoolean("enableSMB_with_COB"), - enableSMB_with_temptarget = determineBasalResult.profile.getBoolean("enableSMB_with_temptarget"), - allowSMB_with_high_temptarget = determineBasalResult.profile.getBoolean("allowSMB_with_high_temptarget"), - enableSMB_always = determineBasalResult.profile.getBoolean("enableSMB_always"), - enableSMB_after_carbs = determineBasalResult.profile.getBoolean("enableSMB_after_carbs"), - maxSMBBasalMinutes = determineBasalResult.profile.getInt("maxSMBBasalMinutes"), - maxUAMSMBBasalMinutes = determineBasalResult.profile.getInt("maxUAMSMBBasalMinutes"), - bolus_increment = determineBasalResult.profile.getDouble("bolus_increment"), - carbsReqThreshold = determineBasalResult.profile.getInt("carbsReqThreshold"), - current_basal = determineBasalResult.profile.getDouble("current_basal"), - temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), - autosens_max = determineBasalResult.profile.getDouble("autosens_max"), - out_units = determineBasalResult.profile.optString("out_units"), - variable_sens = 0.0, - insulinDivisor = 0, - TDD = 0.0 - ) val profile = OapsProfile( dia = 0.0, min_5m_carbimpact = 0.0, @@ -752,7 +707,7 @@ class ReplayApsResultsTest @Inject constructor() { temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), autosens_max = determineBasalResult.profile.getDouble("autosens_max"), out_units = determineBasalResult.profile.optString("out_units"), - variable_sens = determineBasalResult.profile.getDouble("variable_sens"), + variable_sens = 116.7, // TODO only available in result.variableSens? , not in determineBasalResult.profile.getDouble("variable_sens"), insulinDivisor = 0, TDD = 0.0, autoISF_version = determineBasalResult.profile.optString("autoISF_version"), @@ -765,6 +720,8 @@ class ReplayApsResultsTest @Inject constructor() { pp_ISF_hours = determineBasalResult.profile.getInt("pp_ISF_hours"), pp_ISF_weight = determineBasalResult.profile.getDouble("pp_ISF_weight"), delta_ISFrange_weight = determineBasalResult.profile.getDouble("delta_ISFrange_weight"), + lower_ISFrange_weight = determineBasalResult.profile.getDouble("lower_ISFrange_weight"), + higher_ISFrange_weight = determineBasalResult.profile.getDouble("higher_ISFrange_weight"), enable_dura_ISF_with_COB = determineBasalResult.profile.getBoolean("enable_dura_ISF_with_COB"), dura_ISF_weight = determineBasalResult.profile.getDouble("dura_ISF_weight"), smb_delivery_ratio = determineBasalResult.profile.getDouble("smb_delivery_ratio"), @@ -789,17 +746,17 @@ class ReplayApsResultsTest @Inject constructor() { glucose_status = glucoseStatus, currenttemp = currentTemp, iob_data_array = iobData.toTypedArray(), - profile = oprofile, + profile = profile, autosens_data = autosensData, meal_data = meatData, microBolusAllowed = determineBasalResult.microBolusAllowed, currentTime = currentTime, flatBGsDetected = determineBasalResult.flatBGsDetected, - autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf), + autoIsfMode = true, //preferences.get(BooleanKey.ApsUseAutoIsf), iob_threshold_percent = preferences.get(IntKey.ApsAutoIsfIobThPercent), smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension), - profile_percentage = 100, - smb_ratio = 0.5, + profile_percentage = profile.profile_percentage, // 100, + smb_ratio = profile.smb_delivery_ratio, // 0.5, loop_wanted_smb = "dummy", auto_isf_console = mutableListOf("start AutoISF", "end AutoISF") ) @@ -813,11 +770,11 @@ class ReplayApsResultsTest @Inject constructor() { aapsLogger.debug(LTag.APS, "File: $filename") // // assertThat(resultKt.reason.toString()).isEqualTo(result?.json?.getString("reason")) assertThat(resultKt.tick ?: "").isEqualTo(result?.json()?.optString("tick")) -// assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) + assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("targetBG")) assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result?.json()?.optDouble("insulinReq")) -// assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) -// assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) + assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) + assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) assertThat(resultKt.units ?: Double.NaN).isEqualTo(result?.json()?.optDouble("units")) assertThat(resultKt.sensitivityRatio ?: Double.NaN).isEqualTo(result?.json()?.optDouble("sensitivityRatio")) assertThat(resultKt.duration ?: 0).isEqualTo(result?.json()?.optInt("duration")) diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt index 0898e214b00..b9991cd6d77 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt @@ -59,6 +59,8 @@ data class OapsProfile( var pp_ISF_hours: Int = 3, var pp_ISF_weight: Double = 0.0, var delta_ISFrange_weight: Double = 0.0, + var lower_ISFrange_weight: Double = 0.0, + var higher_ISFrange_weight: Double = 0.0, var enable_dura_ISF_with_COB: Boolean = false, var dura_ISF_weight: Double = 0.0, var smb_delivery_ratio: Double = 0.5, diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index f9d80325482..354b732aba0 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -347,6 +347,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( pp_ISF_hours = pp_ISF_hours, pp_ISF_weight = pp_ISF_weight, delta_ISFrange_weight = delta_ISFrange_weight, + lower_ISFrange_weight = lower_ISFrange_weight, + higher_ISFrange_weight = higher_ISFrange_weight, enable_dura_ISF_with_COB = enable_dura_ISF_with_COB, dura_ISF_weight = dura_ISF_weight, smb_delivery_ratio = smb_delivery_ratio, @@ -401,7 +403,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed") aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected") aapsLogger.debug(LTag.APS, "AutoIsfMode: $autoIsfMode") - aapsLogger.debug(LTag.APS, "AutoISF extras: ${Json.encodeToString(OapsProfile.serializer(), oapsProfile)}") + //aapsLogger.debug(LTag.APS, "AutoISF extras: ${Json.encodeToString(OapsProfile.serializer(), oapsProfile)}") determineBasalAutoISF.determine_basal( glucose_status = glucoseStatus, @@ -522,13 +524,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val glucose_status = glucoseStatusProvider.glucoseStatusData // val autoIsfMode = preferences.get(BooleanKey.ApsUseAutoIsf) - if (!supportsDynamicIsf() || !autoIsfWeights || glucose_status == null) { - consoleError.add("autoISF weights disabled in Preferences") - consoleError.add("----------------------------------") - consoleError.add("end AutoISF") - consoleError.add("----------------------------------") - return sens - } val high_temptarget_raises_sensitivity = exerciseMode || highTemptargetRaisesSensitivity val meal_data = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() var target_bg = hardLimits.verifyHardLimits(profile.getTargetMgdl(), app.aaps.core.ui.R.string.temp_target_value, HardLimits.LIMIT_TARGET_BG[0], HardLimits.LIMIT_TARGET_BG[1]) @@ -571,6 +566,13 @@ open class OpenAPSAutoISFPlugin @Inject constructor( sensitivityRatio = autosensResult.ratio // consoleError.add("Autosens ratio: $sensitivityRatio; ") } + if (!supportsDynamicIsf() || !autoIsfWeights || glucose_status == null) { + consoleError.add("autoISF weights disabled in Preferences") + consoleError.add("----------------------------------") + consoleError.add("end AutoISF") + consoleError.add("----------------------------------") + return round(sens / sensitivityRatio, 1) + } val autosensResult = AutosensResult() if (constraintsChecker.isAutosensModeEnabled().value()) { @@ -731,7 +733,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( consoleError.add("----------------------------------") consoleError.add("end AutoISF") consoleError.add("----------------------------------") - return sens // nothing changed + return round(sens / sensitivityRatio, 1) // nothing changed } fun interpolate(xdata: Double, type: String): Double { // interpolate ISF behaviour based on polygons defining nonlinear functions defined by value pairs for ... @@ -970,7 +972,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsMaxBasal, dialogMessage = R.string.openapsma_max_basal_summary, title = R.string.openapsma_max_basal_title)) addPreference(AdaptiveDoublePreference(ctx = context, doubleKey = DoubleKey.ApsSmbMaxIob, dialogMessage = R.string.openapssmb_max_iob_summary, title = R.string.openapssmb_max_iob_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsUseAutosens, title = R.string.openapsama_use_autosens)) - addPreference(AdaptiveUnitPreference(ctx = context, unitKey = UnitDoubleKey.ApsLgsThreshold, dialogMessage = R.string.lgs_threshold_summary, title = R.string.lgs_threshold_title)) + //addPreference(AdaptiveUnitPreference(ctx = context, unitKey = UnitDoubleKey.ApsLgsThreshold, dialogMessage = R.string.lgs_threshold_summary, title = R.string.lgs_threshold_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsSensitivityRaisesTarget, summary = R.string.sensitivity_raises_target_summary, title = R.string.sensitivity_raises_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsResistanceLowersTarget, summary = R.string.resistance_lowers_target_summary, title = R.string.resistance_lowers_target_title)) addPreference(AdaptiveSwitchPreference(ctx = context, booleanKey = BooleanKey.ApsAutoIsfHighTtRaisesSens, summary = R.string.high_temptarget_raises_sensitivity_summary, title = R.string.high_temptarget_raises_sensitivity_title)) diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index b9312ffb6f1..fd7a99941e0 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -117,11 +117,11 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Test fun determine_varSMBratioTest() { - val smb_delivery_ratio = 0.3 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) - val smb_delivery_ratio_min = 0.4 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) - val smb_delivery_ratio_max = 0.6 //preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) - val smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) - val smbMaxRangeExtension = 2.0 //preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatio, 0.3) + preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin, 0.4) + preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax, 0.6) + preferences.put(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange, 20.0) + preferences.put(DoubleKey.ApsAutoIsfSmbMaxRangeExtension, 1.0) val oapsProfile = OapsProfile( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used @@ -165,7 +165,13 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = 100.0, //variableSensitivity, insulinDivisor = 0, - TDD = 0.0 // TODO complete with AutoISF dedicated parameters + TDD = 0.0 , // TODO complete with AutoISF dedicated parameters + smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio), + smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin), + smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax), + smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange), + smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + ) assertThat(openAPSAutoISFPlugin.determine_varSMBratio(oapsProfile,100, 90.0, "fullLoop")).isEqualTo(0.5) } From f6167d95630c8bd94def81fab53d42fb96916b49 Mon Sep 17 00:00:00 2001 From: Philoul Date: Mon, 29 Apr 2024 22:13:15 +0200 Subject: [PATCH 29/38] AutoISF improve code and unit tests --- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 12 ++-- .../OpenAPSAutoISFPluginTest.kt | 64 ++----------------- 2 files changed, 11 insertions(+), 65 deletions(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 354b732aba0..e247a7a0c71 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -69,7 +69,6 @@ import app.aaps.plugins.aps.R import app.aaps.plugins.aps.events.EventOpenAPSUpdateGui import app.aaps.plugins.aps.events.EventResetOpenAPSGui import dagger.android.HasAndroidInjector -import kotlinx.serialization.json.Json import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton @@ -136,7 +135,8 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val smb_delivery_ratio; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio) private val smb_delivery_ratio_min; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin) private val smb_delivery_ratio_max; get() = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax) - private val smb_delivery_ratio_bg_range; get() = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) + private val smb_delivery_ratio_bg_range + get() = if (preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) < 10.0) preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) * GlucoseUnit.MMOLL_TO_MGDL else preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange) val smbMaxRangeExtension; get() = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) private val enableSMB_EvenOn_OddOff; get() = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt) // for TT private val enableSMB_EvenOn_OddOff_always; get() = preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt) // for profile target @@ -391,7 +391,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( val iobTHvirtual = iobThresholdPercent * iobTHtolerance / 10000.0 * oapsProfile.max_iob * iobTH_reduction_ratio val loopWantedSmb = loop_smb(microBolusAllowed, oapsProfile, iobData.iob, use_iobTH, iobTHvirtual / iobTHtolerance * 100.0) val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT - val smbRatio = determine_varSMBratio(oapsProfile, glucoseStatus.glucose.toInt(), target_bg, loopWantedSmb) + val smbRatio = determine_varSMBratio(glucoseStatus.glucose.toInt(), target_bg, loopWantedSmb) aapsLogger.debug(LTag.APS, ">>> Invoking determine_basal AutoISF <<<") aapsLogger.debug(LTag.APS, "Glucose status: $glucoseStatus") @@ -916,11 +916,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return "AAPS" // leave it to standard AAPS } - fun determine_varSMBratio(profile: OapsProfile, bg: Int, target_bg: Double, loop_wanted_smb: String): Double { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target - var smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range - if (smb_delivery_ratio_bg_range < 10) { - smb_delivery_ratio_bg_range = smb_delivery_ratio_bg_range * 18 - } // was in mmol/l + fun determine_varSMBratio(bg: Int, target_bg: Double, loop_wanted_smb: String): Double { // let SMB delivery ratio increase from min to max depending on how much bg exceeds target val fix_SMB: Double = smb_delivery_ratio val lower_SMB = min(smb_delivery_ratio_min, smb_delivery_ratio_max) val higher_SMB = max(smb_delivery_ratio_min, smb_delivery_ratio_max) diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index fd7a99941e0..68811499671 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -25,6 +25,7 @@ import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mock +import org.mockito.Mockito.`when` class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @@ -34,7 +35,6 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Mock lateinit var determineBasalSMB: DetermineBasalAutoISF @Mock lateinit var sharedPrefs: SharedPreferences @Mock lateinit var bgQualityCheck: BgQualityCheck - @Mock lateinit var tddCalculator: TddCalculator @Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var profiler: Profiler private lateinit var openAPSAutoISFPlugin: OpenAPSAutoISFPlugin @@ -117,62 +117,12 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Test fun determine_varSMBratioTest() { - preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatio, 0.3) - preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin, 0.4) - preferences.put(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax, 0.6) - preferences.put(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange, 20.0) - preferences.put(DoubleKey.ApsAutoIsfSmbMaxRangeExtension, 1.0) - val oapsProfile = OapsProfile( - dia = 0.0, // not used - min_5m_carbimpact = 0.0, // not used - max_iob = 8.0, //constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), - max_daily_basal = 0.4, //profile.getMaxDailyBasal(), - max_basal = 0.4, //constraintsChecker.getMaxBasalAllowed(profile).also { inputConstraints.copyReasons(it) }.value(), - min_bg = 90.0, - max_bg = 90.0, - target_bg = 90.0, - carb_ratio = 10.0, //profile.getIc(), - sens = 100.0, //sens, - autosens_adjust_targets = false, // not used - max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), - current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), - lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), - high_temptarget_raises_sensitivity = preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens), //exerciseMode || highTemptargetRaisesSensitivity, //was false, - low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, - sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), - resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), - adv_target_adjustments = SMBDefaults.adv_target_adjustments, - exercise_mode = SMBDefaults.exercise_mode, - half_basal_exercise_target = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), - maxCOB = SMBDefaults.maxCOB, - skip_neutral_temps = false, //pump.setNeutralTempAtFullHour(), - remainingCarbsCap = SMBDefaults.remainingCarbsCap, - enableUAM = true, //constraintsChecker.isUAMEnabled().also { inputConstraints.copyReasons(it) }.value(), - A52_risk_enable = SMBDefaults.A52_risk_enable, - SMBInterval = preferences.get(IntKey.ApsMaxSmbFrequency), - enableSMB_with_COB = preferences.get(BooleanKey.ApsUseSmbWithCob), //smbEnabled && - enableSMB_with_temptarget = preferences.get(BooleanKey.ApsUseSmbWithLowTt), //smbEnabled && - allowSMB_with_high_temptarget = preferences.get(BooleanKey.ApsUseSmbWithHighTt), //smbEnabled && - enableSMB_always = preferences.get(BooleanKey.ApsUseSmbAlways), //smbEnabled && && advancedFiltering, - enableSMB_after_carbs = preferences.get(BooleanKey.ApsUseSmbAfterCarbs), //smbEnabled && && advancedFiltering, - maxSMBBasalMinutes = preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb), - maxUAMSMBBasalMinutes = preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb), - bolus_increment = 0.1, //pump.pumpDescription.bolusStep, - carbsReqThreshold = preferences.get(IntKey.ApsCarbsRequestThreshold), - current_basal = activePlugin.activePump.baseBasalRate, - temptargetSet = false, - autosens_max = preferences.get(DoubleKey.AutosensMax), - out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", - variable_sens = 100.0, //variableSensitivity, - insulinDivisor = 0, - TDD = 0.0 , // TODO complete with AutoISF dedicated parameters - smb_delivery_ratio = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio), - smb_delivery_ratio_min = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin), - smb_delivery_ratio_max = preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax), - smb_delivery_ratio_bg_range = preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange), - smb_max_range_extension = preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension) + `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio)).thenReturn(0.3) + `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin)).thenReturn(0.4) + `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax)).thenReturn(0.6) + `when`(preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange)).thenReturn(20.0) + `when`(preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension)).thenReturn(1.0) - ) - assertThat(openAPSAutoISFPlugin.determine_varSMBratio(oapsProfile,100, 90.0, "fullLoop")).isEqualTo(0.5) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(100, 90.0, "fullLoop")).isEqualTo(0.5) } } From 32ab4d6afc405da6398ed3d9f5b523d2befbc2fa Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Mon, 6 May 2024 00:47:47 +0200 Subject: [PATCH 30/38] add more AutoISF unit tests and fix mmol conversion --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 3 +- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 9 +- .../OpenAPSAutoISFPluginTest.kt | 207 +++++++++++++++++- 3 files changed, 210 insertions(+), 9 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 46e397afddb..faee3edf27a 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -600,6 +600,7 @@ class ReplayApsResultsTest @Inject constructor() { determineBasalResult.currentTime = input.getLong("currentTime") determineBasalResult.flatBGsDetected = input.getBoolean("flatBGsDetected") val result = determineBasalResult.invoke() + val varSens = result?.variableSens!! val endJs = System.currentTimeMillis() jsTime += (endJs - startJs) @@ -707,7 +708,7 @@ class ReplayApsResultsTest @Inject constructor() { temptargetSet = determineBasalResult.profile.getBoolean("temptargetSet"), autosens_max = determineBasalResult.profile.getDouble("autosens_max"), out_units = determineBasalResult.profile.optString("out_units"), - variable_sens = 116.7, // TODO only available in result.variableSens? , not in determineBasalResult.profile.getDouble("variable_sens"), + variable_sens = varSens, // TODO only available in result.variableSens? , not in determineBasalResult.profile.getDouble("variable_sens"), insulinDivisor = 0, TDD = 0.0, autoISF_version = determineBasalResult.profile.optString("autoISF_version"), diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index e247a7a0c71..e4cfb059342 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -10,6 +10,7 @@ import androidx.preference.PreferenceManager import androidx.preference.PreferenceScreen import androidx.preference.SwitchPreference import app.aaps.core.data.aps.SMBDefaults +import app.aaps.core.data.configuration.Constants import app.aaps.core.data.model.GlucoseUnit import app.aaps.core.data.plugin.PluginType import app.aaps.core.data.time.T @@ -364,7 +365,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( //done calculate exercise ratio var exerciseRatio = 1.0 // TODO eliminate - var origin_sens = "" val target_bg = (minBg + maxBg) / 2 if (highTemptargetRaisesSensitivity && isTempTarget && target_bg > normalTarget || oapsProfile.low_temptarget_lowers_sensitivity && isTempTarget && target_bg < normalTarget @@ -519,6 +519,9 @@ open class OpenAPSAutoISFPlugin @Inject constructor( fun convert_bg(value: Double): String = profileUtil.fromMgdlToStringInUnits(value).replace("-0.0", "0.0") + fun convert_bg_to_units(value: Double, profile: OapsProfile): Double = + if (profile.out_units == "mmol/L") value * Constants.MGDL_TO_MMOLL else value + fun autoISF(currentTime: Long, profile: Profile): Double { val sens = profile.getProfileIsfMgdl() val glucose_status = glucoseStatusProvider.glucoseStatusData @@ -850,13 +853,13 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return "AAPS" // see message in enable_smb } if (profile.temptargetSet && enableSMB_EvenOn_OddOff || profile.min_bg == profile.max_bg && enableSMB_EvenOn_OddOff_always && !profile.temptargetSet) { - val target = convert_bg(profile.target_bg) + //TODO: cleaner conversion back to original mmol/L if applicable + var target = convert_bg_to_units(profile.target_bg, profile) val msgType: String val evenTarget: Boolean val msgUnits: String val msgTail: String val msgEven: String - val msg: String msgType = if (profile.temptargetSet) { "TempTarget" } else { diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index 68811499671..682a996af20 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -2,13 +2,11 @@ package app.aaps.plugins.aps.openAPSAutoISF import android.content.SharedPreferences import app.aaps.core.data.aps.SMBDefaults -import app.aaps.core.data.model.GlucoseUnit import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck import app.aaps.core.interfaces.constraints.ConstraintsChecker import app.aaps.core.interfaces.db.PersistenceLayer import app.aaps.core.interfaces.iob.GlucoseStatusProvider import app.aaps.core.interfaces.profiling.Profiler -import app.aaps.core.interfaces.stats.TddCalculator import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.aps.OapsProfile import app.aaps.core.keys.AdaptiveIntentPreference @@ -117,12 +115,211 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Test fun determine_varSMBratioTest() { - `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio)).thenReturn(0.3) + `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatio)).thenReturn(0.55) `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMin)).thenReturn(0.4) `when`(preferences.get(DoubleKey.ApsAutoIsfSmbDeliveryRatioMax)).thenReturn(0.6) `when`(preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange)).thenReturn(20.0) - `when`(preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension)).thenReturn(1.0) + //`when`(preferences.get(DoubleKey.ApsAutoIsfSmbMaxRangeExtension)).thenReturn(1.0) + + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(100, 90.0, "fullLoop")).isEqualTo(0.55) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(180, 90.0, "fullLoop")).isEqualTo(0.6) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(100, 90.0, "enforced")).isEqualTo(0.5) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(80, 90.0, "enforced")).isEqualTo(0.4) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(180, 90.0, "enforced")).isEqualTo(0.6) + `when`(preferences.get(UnitDoubleKey.ApsAutoIsfSmbDeliveryRatioBgRange)).thenReturn(0.0) + assertThat(openAPSAutoISFPlugin.determine_varSMBratio(180, 90.0, "enforced")).isEqualTo(0.55) + } + + @Test + fun interpolateTest() { + `when`(preferences.get(DoubleKey.ApsAutoIsfLowBgWeight)).thenReturn(10.0) + `when`(preferences.get(DoubleKey.ApsAutoIsfHighBgWeight)).thenReturn(1.0) + assertThat(openAPSAutoISFPlugin.interpolate(45.0, "bg")).isEqualTo(-5.0) + assertThat(openAPSAutoISFPlugin.interpolate(55.0, "bg")).isEqualTo(-5.0) + assertThat(openAPSAutoISFPlugin.interpolate(100.0, "bg")).isEqualTo(0.0) + assertThat(openAPSAutoISFPlugin.interpolate(130.0, "bg")).isEqualTo(0.25) + assertThat(openAPSAutoISFPlugin.interpolate(230.0, "bg")).isEqualTo(0.7) + } + + @Test + fun loop_smbTest() { + val profile = OapsProfile( + dia = 0.0, // not used + min_5m_carbimpact = 0.0, // not used + max_iob = 10.0, + max_daily_basal = 0.5, + max_basal = 0.0, + min_bg = 90.0, + max_bg = 90.0, + target_bg = 90.0, + carb_ratio = 10.0, + sens = 100.0, + autosens_adjust_targets = false, // not used + max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), + current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), + lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), + high_temptarget_raises_sensitivity = false, + low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, + sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), + resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), + adv_target_adjustments = SMBDefaults.adv_target_adjustments, + exercise_mode = SMBDefaults.exercise_mode, + half_basal_exercise_target = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), + maxCOB = SMBDefaults.maxCOB, + skip_neutral_temps = false, + remainingCarbsCap = SMBDefaults.remainingCarbsCap, + enableUAM = false, + A52_risk_enable = SMBDefaults.A52_risk_enable, + SMBInterval = preferences.get(IntKey.ApsMaxSmbFrequency), + enableSMB_with_COB = true, + enableSMB_with_temptarget = true, + allowSMB_with_high_temptarget = false, + enableSMB_always = true, + enableSMB_after_carbs = true, + maxSMBBasalMinutes = preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb), + maxUAMSMBBasalMinutes = preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb), + bolus_increment = 0.1, + carbsReqThreshold = preferences.get(IntKey.ApsCarbsRequestThreshold), + current_basal = activePlugin.activePump.baseBasalRate, + temptargetSet = true, + autosens_max = preferences.get(DoubleKey.AutosensMax), + out_units = "mg/dl", + variable_sens = 111.1, + insulinDivisor = 0, + TDD = 0.0, + autoISF_version = "3.0", + enable_autoISF = true, + autoISF_max = 1.5, + autoISF_min = 0.7, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = true, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = true, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.5, + smb_delivery_ratio_min = 0.6, + smb_delivery_ratio_max = 1.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = true, + enableSMB_EvenOn_OddOff_always = true, + iob_threshold_percent = 100, + profile_percentage = 100 + ) + assertThat(openAPSAutoISFPlugin.loop_smb(false, profile, 11.0, false, 11.1)).isEqualTo("AAPS") + `when`(preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt)).thenReturn(true) + `when`(preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt)).thenReturn(true) + assertThat(openAPSAutoISFPlugin.loop_smb(true, profile, 11.0, false, 11.1)).isEqualTo("fullLoop") + assertThat(openAPSAutoISFPlugin.loop_smb(true, profile, 11.0, true, 10.1)).isEqualTo("iobTH") + profile.target_bg = 122.0 + assertThat(openAPSAutoISFPlugin.loop_smb(true, profile, 11.0, false, 11.1)).isEqualTo("enforced") + profile.target_bg = 91.8 //5.1 + profile.out_units = "mmol/L" + assertThat(openAPSAutoISFPlugin.loop_smb(true, profile, 11.0, false, 11.1)).isEqualTo("blocked") + `when`(preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenPt)).thenReturn(false) + `when`(preferences.get(BooleanKey.ApsAutoIsfSmbOnEvenTt)).thenReturn(false) + assertThat(openAPSAutoISFPlugin.loop_smb(true, profile, 11.0, false, 11.1)).isEqualTo("AAPS") + } + + @Test + fun autoISFTest() { + // TODO get profile + val profile = profileFunction.getProfile(now) + if ( profile == null) return + + val oapsProfile = OapsProfile( + dia = 0.0, // not used + min_5m_carbimpact = 0.0, // not used + max_iob = 10.0, + max_daily_basal = 0.5, + max_basal = 0.0, + min_bg = 91.0, + max_bg = 91.0, + target_bg = 91.0, + carb_ratio = 10.0, + sens = 100.0, + autosens_adjust_targets = false, // not used + max_daily_safety_multiplier = preferences.get(DoubleKey.ApsMaxDailyMultiplier), + current_basal_safety_multiplier = preferences.get(DoubleKey.ApsMaxCurrentBasalMultiplier), + lgsThreshold = profileUtil.convertToMgdlDetect(preferences.get(UnitDoubleKey.ApsLgsThreshold)).toInt(), + high_temptarget_raises_sensitivity = false, + low_temptarget_lowers_sensitivity = preferences.get(BooleanKey.ApsAutoIsfLowTtLowersSens), // was false, + sensitivity_raises_target = preferences.get(BooleanKey.ApsSensitivityRaisesTarget), + resistance_lowers_target = preferences.get(BooleanKey.ApsResistanceLowersTarget), + adv_target_adjustments = SMBDefaults.adv_target_adjustments, + exercise_mode = SMBDefaults.exercise_mode, + half_basal_exercise_target = preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget), + maxCOB = SMBDefaults.maxCOB, + skip_neutral_temps = false, + remainingCarbsCap = SMBDefaults.remainingCarbsCap, + enableUAM = false, + A52_risk_enable = SMBDefaults.A52_risk_enable, + SMBInterval = preferences.get(IntKey.ApsMaxSmbFrequency), + enableSMB_with_COB = true, + enableSMB_with_temptarget = true, + allowSMB_with_high_temptarget = false, + enableSMB_always = true, + enableSMB_after_carbs = true, + maxSMBBasalMinutes = preferences.get(IntKey.ApsMaxMinutesOfBasalToLimitSmb), + maxUAMSMBBasalMinutes = preferences.get(IntKey.ApsUamMaxMinutesOfBasalToLimitSmb), + bolus_increment = 0.1, + carbsReqThreshold = preferences.get(IntKey.ApsCarbsRequestThreshold), + current_basal = activePlugin.activePump.baseBasalRate, + temptargetSet = true, + autosens_max = preferences.get(DoubleKey.AutosensMax), + out_units = "mg/dl", + variable_sens = 47.11, + insulinDivisor = 0, + TDD = 0.0, + autoISF_version = "3.0", + enable_autoISF = false, + autoISF_max = 1.5, + autoISF_min = 0.7, + bgAccel_ISF_weight = 0.0, + bgBrake_ISF_weight = 0.0, + enable_pp_ISF_always = true, + pp_ISF_hours = 3, + pp_ISF_weight = 0.0, + delta_ISFrange_weight = 0.0, + lower_ISFrange_weight = 0.0, + higher_ISFrange_weight = 0.0, + enable_dura_ISF_with_COB = true, + dura_ISF_weight = 0.0, + smb_delivery_ratio = 0.5, + smb_delivery_ratio_min = 0.6, + smb_delivery_ratio_max = 1.0, + smb_delivery_ratio_bg_range = 0.0, + smb_max_range_extension = 1.0, + enableSMB_EvenOn_OddOff = true, + enableSMB_EvenOn_OddOff_always = true, + iob_threshold_percent = 100, + profile_percentage = 100 + ) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11) // inactive + `when`(oapsProfile.enable_autoISF).thenReturn(true) + val glucose_status = glucoseStatusProvider.glucoseStatusData!! + `when`(glucose_status.corrSqu).thenReturn(0.4711) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11) // bad parabola + `when`(preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens)).thenReturn(true) + `when`(preferences.get(IntKey.ApsAutoIsfHalfBasalExerciseTarget)).thenReturn(160) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11 * 2.0) // exercise mode w/o AutoISF + `when`(glucose_status.corrSqu).thenReturn(0.95) + `when`(glucose_status.glucose).thenReturn(90.0) + `when`(glucose_status.a0).thenReturn(90.3) + `when`(glucose_status.a1).thenReturn(2.0) + `when`(glucose_status.a2).thenReturn(3.0) + `when`(glucose_status.bgAcceleration).thenReturn(2.0 * glucose_status.a2) + `when`(preferences.get(DoubleKey.ApsAutoIsfBgAccelWeight)).thenReturn(2.0) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11 * 2.0 * 2.0) // acce_ISF + exercise mode + `when`(preferences.get(BooleanKey.ApsAutoIsfHighTtRaisesSens)).thenReturn(false) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11 * 2.0) // acce_ISF w/o exercise mode + `when`(preferences.get(DoubleKey.ApsAutoIsfLowBgWeight)).thenReturn(2.0) + assertThat(openAPSAutoISFPlugin.autoISF(now, profile)).isEqualTo(47.11 * 1.0) // bg_ISF strengthened by acce_ISF - assertThat(openAPSAutoISFPlugin.determine_varSMBratio(100, 90.0, "fullLoop")).isEqualTo(0.5) } } From 679948c2d27bc866afa73665890d30b4fe099884 Mon Sep 17 00:00:00 2001 From: Philoul Date: Tue, 7 May 2024 14:32:33 +0200 Subject: [PATCH 31/38] AutoISF Dev + Engineering mode only --- .../app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index e4cfb059342..46742d4744e 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -109,7 +109,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( .shortName(R.string.autoisf_shortname) .preferencesId(PluginDescription.PREFERENCE_SCREEN) .preferencesVisibleInSimpleMode(false) - .showInList(config.APS) + .showInList(config.isEngineeringMode() && config.isDev()) .description(R.string.description_auto_isf), aapsLogger, rh ), APS, PluginConstraints { From e1f655c18a1eb24114fd15b43fe4da2d624aae5d Mon Sep 17 00:00:00 2001 From: Philoul Date: Wed, 8 May 2024 01:46:06 +0200 Subject: [PATCH 32/38] Add OapsProfileIsf --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 3 +- .../app/aaps/core/interfaces/aps/APSResult.kt | 1 + .../aaps/core/interfaces/aps/OapsProfile.kt | 26 +------ .../core/interfaces/aps/OapsProfileAutoIsf.kt | 75 +++++++++++++++++++ .../core/objects/aps/DetermineBasalResult.kt | 2 + .../converters/APSResultExtension.kt | 35 +++++++-- .../app/aaps/plugins/aps/OpenAPSFragment.kt | 2 +- .../openAPSAutoISF/DetermineBasalAutoISF.kt | 11 ++- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 12 ++- .../OpenAPSAutoISFPluginTest.kt | 10 +-- 10 files changed, 125 insertions(+), 52 deletions(-) create mode 100644 core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index faee3edf27a..61a3a014c38 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -10,6 +10,7 @@ import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.maintenance.FileListProvider @@ -667,7 +668,7 @@ class ReplayApsResultsTest @Inject constructor() { for (i in 0 until determineBasalResult.iobData!!.length()) iobData.add(determineBasalResult.iobData!!.getJSONObject(i).toIob()) val currentTime = determineBasalResult.currentTime - val profile = OapsProfile( + val profile = OapsProfileAutoIsf( dia = 0.0, min_5m_carbimpact = 0.0, max_iob = determineBasalResult.profile.getDouble("max_iob"), diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/APSResult.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/APSResult.kt index bd46d233de3..74eefda97ec 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/APSResult.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/APSResult.kt @@ -43,6 +43,7 @@ interface APSResult { var glucoseStatus: GlucoseStatus? var currentTemp: CurrentTemp? var oapsProfile: OapsProfile? + var oapsProfileAutoIsf: OapsProfileAutoIsf? var mealData: MealData? val iob: IobTotal? get() = iobData?.get(0) diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt index b9991cd6d77..5dbbe01c4eb 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfile.kt @@ -47,29 +47,5 @@ data class OapsProfile( //DynISF only var variable_sens: Double, var insulinDivisor: Int, - var TDD: Double, - //AutoISF only - var autoISF_version: String = "", - var enable_autoISF: Boolean = true, - var autoISF_max: Double = 1.0, - var autoISF_min: Double = 1.0, - var bgAccel_ISF_weight: Double = 0.0, - var bgBrake_ISF_weight: Double = 0.0, - var enable_pp_ISF_always: Boolean = false, - var pp_ISF_hours: Int = 3, - var pp_ISF_weight: Double = 0.0, - var delta_ISFrange_weight: Double = 0.0, - var lower_ISFrange_weight: Double = 0.0, - var higher_ISFrange_weight: Double = 0.0, - var enable_dura_ISF_with_COB: Boolean = false, - var dura_ISF_weight: Double = 0.0, - var smb_delivery_ratio: Double = 0.5, - var smb_delivery_ratio_min: Double = 0.5, - var smb_delivery_ratio_max: Double = 0.5, - var smb_delivery_ratio_bg_range: Double = 0.0, - var smb_max_range_extension: Double = 1.0, - var enableSMB_EvenOn_OddOff: Boolean = false, - var enableSMB_EvenOn_OddOff_always: Boolean = false, - var iob_threshold_percent: Int = 100, - var profile_percentage: Int = 100 + var TDD: Double ) \ No newline at end of file diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt new file mode 100644 index 00000000000..2e7523eee33 --- /dev/null +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt @@ -0,0 +1,75 @@ +package app.aaps.core.interfaces.aps + +import kotlinx.serialization.Serializable + +@Serializable +data class OapsProfileAutoIsf( + var dia: Double, // AMA only + var min_5m_carbimpact: Double, // AMA only + var max_iob: Double, + var max_daily_basal: Double, + var max_basal: Double, + var min_bg: Double, + var max_bg: Double, + var target_bg: Double, + var carb_ratio: Double, + var sens: Double, + var autosens_adjust_targets: Boolean, // AMA only + var max_daily_safety_multiplier: Double, + var current_basal_safety_multiplier: Double, + var high_temptarget_raises_sensitivity: Boolean, + var low_temptarget_lowers_sensitivity: Boolean, + var sensitivity_raises_target: Boolean, + var resistance_lowers_target: Boolean, + var adv_target_adjustments: Boolean, + var exercise_mode: Boolean, + var half_basal_exercise_target: Int, + var maxCOB: Int, + var skip_neutral_temps: Boolean, + var remainingCarbsCap: Int, + var enableUAM: Boolean, + var A52_risk_enable: Boolean, + var SMBInterval: Int, + var enableSMB_with_COB: Boolean, + var enableSMB_with_temptarget: Boolean, + var allowSMB_with_high_temptarget: Boolean, + var enableSMB_always: Boolean, + var enableSMB_after_carbs: Boolean, + var maxSMBBasalMinutes: Int, + var maxUAMSMBBasalMinutes: Int, + var bolus_increment: Double, + var carbsReqThreshold: Int, + var current_basal: Double, + var temptargetSet: Boolean, + var autosens_max: Double, + var out_units: String, + var lgsThreshold: Int?, + //DynISF only + var variable_sens: Double, + var insulinDivisor: Int, + var TDD: Double, + //AutoISF only + var autoISF_version: String = "", + var enable_autoISF: Boolean = true, + var autoISF_max: Double = 1.0, + var autoISF_min: Double = 1.0, + var bgAccel_ISF_weight: Double = 0.0, + var bgBrake_ISF_weight: Double = 0.0, + var enable_pp_ISF_always: Boolean = false, + var pp_ISF_hours: Int = 3, + var pp_ISF_weight: Double = 0.0, + var delta_ISFrange_weight: Double = 0.0, + var lower_ISFrange_weight: Double = 0.0, + var higher_ISFrange_weight: Double = 0.0, + var enable_dura_ISF_with_COB: Boolean = false, + var dura_ISF_weight: Double = 0.0, + var smb_delivery_ratio: Double = 0.5, + var smb_delivery_ratio_min: Double = 0.5, + var smb_delivery_ratio_max: Double = 0.5, + var smb_delivery_ratio_bg_range: Double = 0.0, + var smb_max_range_extension: Double = 1.0, + var enableSMB_EvenOn_OddOff: Boolean = false, + var enableSMB_EvenOn_OddOff_always: Boolean = false, + var iob_threshold_percent: Int = 100, + var profile_percentage: Int = 100 +) \ No newline at end of file diff --git a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt index 58ac79fd5af..880306bd8fe 100644 --- a/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt +++ b/core/objects/src/main/kotlin/app/aaps/core/objects/aps/DetermineBasalResult.kt @@ -12,6 +12,7 @@ import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.constraints.Constraint @@ -79,6 +80,7 @@ class DetermineBasalResult @Inject constructor(val injector: HasAndroidInjector) override var glucoseStatus: GlucoseStatus? = null override var currentTemp: CurrentTemp? = null override var oapsProfile: OapsProfile? = null + override var oapsProfileAutoIsf: OapsProfileAutoIsf? = null override var mealData: MealData? = null lateinit var result: RT diff --git a/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt b/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt index fa808549e38..875c799e79c 100644 --- a/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt +++ b/database/persistence/src/main/kotlin/app/aaps/database/persistence/converters/APSResultExtension.kt @@ -7,6 +7,7 @@ import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.aps.RT import app.aaps.core.objects.aps.DetermineBasalResult import dagger.android.HasAndroidInjector @@ -17,8 +18,7 @@ import kotlinx.serialization.json.Json fun app.aaps.database.entities.APSResult.fromDb(injector: HasAndroidInjector): APSResult = when (algorithm) { app.aaps.database.entities.APSResult.Algorithm.AMA, - app.aaps.database.entities.APSResult.Algorithm.SMB, - app.aaps.database.entities.APSResult.Algorithm.AUTO_ISF -> + app.aaps.database.entities.APSResult.Algorithm.SMB -> DetermineBasalResult(injector, Json.decodeFromString(this.resultJson)).also { result -> result.date = this.timestamp result.glucoseStatus = this.glucoseStatusJson?.let { Json.decodeFromString(it) } @@ -29,15 +29,25 @@ fun app.aaps.database.entities.APSResult.fromDb(injector: HasAndroidInjector): A result.autosensResult = this.autosensDataJson?.let { Json.decodeFromString(it) } } - else -> error("Unsupported") + app.aaps.database.entities.APSResult.Algorithm.AUTO_ISF -> + DetermineBasalResult(injector, Json.decodeFromString(this.resultJson)).also { result -> + result.date = this.timestamp + result.glucoseStatus = this.glucoseStatusJson?.let { Json.decodeFromString(it) } + result.currentTemp = this.currentTempJson?.let { Json.decodeFromString(it) } + result.iobData = this.iobDataJson?.let { Json.decodeFromString(it) } + result.oapsProfileAutoIsf = this.profileJson?.let { Json.decodeFromString(it) } + result.mealData = this.mealDataJson?.let { Json.decodeFromString(it) } + result.autosensResult = this.autosensDataJson?.let { Json.decodeFromString(it) } + } + + else -> error("Unsupported") } @OptIn(ExperimentalSerializationApi::class) fun APSResult.toDb(): app.aaps.database.entities.APSResult = when (algorithm) { APSResult.Algorithm.AMA, - APSResult.Algorithm.SMB, - APSResult.Algorithm.AUTO_ISF -> + APSResult.Algorithm.SMB -> app.aaps.database.entities.APSResult( timestamp = this.date, algorithm = this.algorithm.toDb(), @@ -50,7 +60,20 @@ fun APSResult.toDb(): app.aaps.database.entities.APSResult = resultJson = Json.encodeToString(RT.serializer(), this.rawData() as RT) ) - else -> error("Unsupported") + APSResult.Algorithm.AUTO_ISF -> + app.aaps.database.entities.APSResult( + timestamp = this.date, + algorithm = this.algorithm.toDb(), + glucoseStatusJson = this.glucoseStatus?.let { Json.encodeToString(GlucoseStatus.serializer(), it) }, + currentTempJson = this.currentTemp?.let { Json.encodeToString(CurrentTemp.serializer(), it) }, + iobDataJson = this.iobData?.let { Json.encodeToString(ArraySerializer(IobTotal.serializer()), it) }, + profileJson = this.oapsProfileAutoIsf?.let { Json.encodeToString(OapsProfileAutoIsf.serializer(), it) }, + mealDataJson = this.mealData?.let { Json.encodeToString(MealData.serializer(), it) }, + autosensDataJson = this.autosensResult?.let { Json.encodeToString(AutosensResult.serializer(), it) }, + resultJson = Json.encodeToString(RT.serializer(), this.rawData() as RT) + ) + + else -> error("Unsupported") } fun app.aaps.database.entities.APSResult.Algorithm.fromDb(): APSResult.Algorithm = diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt index f7fe7035844..14ef9565b29 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/OpenAPSFragment.kt @@ -134,7 +134,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider { binding.glucosestatus.text = lastAPSResult.glucoseStatus?.dataClassToHtml(listOf("glucose", "delta", "shortAvgDelta", "longAvgDelta")) binding.currenttemp.text = lastAPSResult.currentTemp?.dataClassToHtml() binding.iobdata.text = rh.gs(R.string.array_of_elements, lastAPSResult.iobData?.size) + "\n" + lastAPSResult.iob?.dataClassToHtml() - binding.profile.text = lastAPSResult.oapsProfile?.dataClassToHtml() + binding.profile.text = lastAPSResult.oapsProfile?.dataClassToHtml() ?: lastAPSResult.oapsProfileAutoIsf?.dataClassToHtml() binding.mealdata.text = lastAPSResult.mealData?.dataClassToHtml() binding.scriptdebugdata.text = lastAPSResult.scriptDebug?.joinToString("\n") binding.constraints.text = lastAPSResult.inputConstraints?.getReasons() diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt index 7884b85752d..75dd2ed7b0e 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/DetermineBasalAutoISF.kt @@ -6,11 +6,10 @@ import app.aaps.core.interfaces.aps.CurrentTemp import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData -import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.aps.RT import app.aaps.core.interfaces.profile.ProfileUtil -import app.aaps.plugins.aps.openAPSAutoISF.OpenAPSAutoISFPlugin import java.text.DecimalFormat import java.time.Instant import java.time.ZoneId @@ -60,7 +59,7 @@ class DetermineBasalAutoISF @Inject constructor( //if (profile.out_units === "mmol/L") round(value / 18, 1).toFixed(1); //else Math.round(value); - fun enable_smb(profile: OapsProfile, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { + fun enable_smb(profile: OapsProfileAutoIsf, microBolusAllowed: Boolean, meal_data: MealData, target_bg: Double): Boolean { // disable SMB when a high temptarget is set if (!microBolusAllowed) { consoleError.add("SMB disabled (!microBolusAllowed)") @@ -105,10 +104,10 @@ class DetermineBasalAutoISF @Inject constructor( consoleError.add(msg) } - private fun getMaxSafeBasal(profile: OapsProfile): Double = + private fun getMaxSafeBasal(profile: OapsProfileAutoIsf): Double = min(profile.max_basal, min(profile.max_daily_safety_multiplier * profile.max_daily_basal, profile.current_basal_safety_multiplier * profile.current_basal)) - fun setTempBasal(_rate: Double, duration: Int, profile: OapsProfile, rT: RT, currenttemp: CurrentTemp): RT { + fun setTempBasal(_rate: Double, duration: Int, profile: OapsProfileAutoIsf, rT: RT, currenttemp: CurrentTemp): RT { //var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); val maxSafeBasal = getMaxSafeBasal(profile) @@ -148,7 +147,7 @@ class DetermineBasalAutoISF @Inject constructor( fun determine_basal( - glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfile, autosens_data: AutosensResult, meal_data: MealData, + glucose_status: GlucoseStatus, currenttemp: CurrentTemp, iob_data_array: Array, profile: OapsProfileAutoIsf, autosens_data: AutosensResult, meal_data: MealData, microBolusAllowed: Boolean, currentTime: Long, flatBGsDetected: Boolean, autoIsfMode: Boolean, loop_wanted_smb: String, profile_percentage: Int, smb_ratio: Double, smb_max_range_extension: Double, iob_threshold_percent: Int, auto_isf_console: MutableList ): RT { diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index 46742d4744e..b5e513c764a 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -18,7 +18,7 @@ import app.aaps.core.interfaces.aps.APS import app.aaps.core.interfaces.aps.APSResult import app.aaps.core.interfaces.aps.AutosensResult import app.aaps.core.interfaces.aps.CurrentTemp -import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.bgQualityCheck.BgQualityCheck import app.aaps.core.interfaces.configuration.Config import app.aaps.core.interfaces.constraints.Constraint @@ -40,7 +40,6 @@ import app.aaps.core.interfaces.profiling.Profiler import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.events.EventAPSCalculationFinished -import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.HardLimits import app.aaps.core.interfaces.utils.Round @@ -97,7 +96,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( private val persistenceLayer: PersistenceLayer, private val glucoseStatusProvider: GlucoseStatusProvider, private val bgQualityCheck: BgQualityCheck, - private val uiInteraction: UiInteraction, private val determineBasalAutoISF: DetermineBasalAutoISF, private val profiler: Profiler ) : PluginBase( @@ -294,7 +292,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( consoleError = mutableListOf() variableSensitivity = autoISF(now, profile) } - val oapsProfile = OapsProfile( + val oapsProfile = OapsProfileAutoIsf( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used max_iob = constraintsChecker.getMaxIOBAllowed().also { inputConstraints.copyReasons(it) }.value(), @@ -430,7 +428,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( determineBasalResult.iobData = iobArray determineBasalResult.glucoseStatus = glucoseStatus determineBasalResult.currentTemp = currentTemp - determineBasalResult.oapsProfile = oapsProfile + determineBasalResult.oapsProfileAutoIsf = oapsProfile determineBasalResult.mealData = mealData lastAPSResult = determineBasalResult lastAPSRun = now @@ -519,7 +517,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( fun convert_bg(value: Double): String = profileUtil.fromMgdlToStringInUnits(value).replace("-0.0", "0.0") - fun convert_bg_to_units(value: Double, profile: OapsProfile): Double = + fun convert_bg_to_units(value: Double, profile: OapsProfileAutoIsf): Double = if (profile.out_units == "mmol/L") value * Constants.MGDL_TO_MMOLL else value fun autoISF(currentTime: Long, profile: Profile): Double { @@ -848,7 +846,7 @@ open class OpenAPSAutoISFPlugin @Inject constructor( return finalISF } - fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfile, iob_data_iob: Double, useIobTh: Boolean, iobThEffective: Double): String { + fun loop_smb(microBolusAllowed: Boolean, profile: OapsProfileAutoIsf, iob_data_iob: Double, useIobTh: Boolean, iobThEffective: Double): String { if (!microBolusAllowed) { return "AAPS" // see message in enable_smb } diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index 682a996af20..599960a3598 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -7,8 +7,7 @@ import app.aaps.core.interfaces.constraints.ConstraintsChecker import app.aaps.core.interfaces.db.PersistenceLayer import app.aaps.core.interfaces.iob.GlucoseStatusProvider import app.aaps.core.interfaces.profiling.Profiler -import app.aaps.core.interfaces.ui.UiInteraction -import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.keys.AdaptiveIntentPreference import app.aaps.core.keys.BooleanKey import app.aaps.core.keys.DoubleKey @@ -33,7 +32,6 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Mock lateinit var determineBasalSMB: DetermineBasalAutoISF @Mock lateinit var sharedPrefs: SharedPreferences @Mock lateinit var bgQualityCheck: BgQualityCheck - @Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var profiler: Profiler private lateinit var openAPSAutoISFPlugin: OpenAPSAutoISFPlugin @@ -71,7 +69,7 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { openAPSAutoISFPlugin = OpenAPSAutoISFPlugin( injector, aapsLogger, rxBus, constraintChecker, rh, profileFunction, profileUtil, config, activePlugin, iobCobCalculator, hardLimits, preferences, dateUtil, processedTbrEbData, persistenceLayer, glucoseStatusProvider, - bgQualityCheck, uiInteraction, determineBasalSMB, profiler + bgQualityCheck, determineBasalSMB, profiler ) } @@ -143,7 +141,7 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { @Test fun loop_smbTest() { - val profile = OapsProfile( + val profile = OapsProfileAutoIsf( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used max_iob = 10.0, @@ -232,7 +230,7 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { val profile = profileFunction.getProfile(now) if ( profile == null) return - val oapsProfile = OapsProfile( + val oapsProfile = OapsProfileAutoIsf( dia = 0.0, // not used min_5m_carbimpact = 0.0, // not used max_iob = 10.0, From 19afd31047e609c4715ba1c60e60bcb658e42726 Mon Sep 17 00:00:00 2001 From: Philoul Date: Wed, 8 May 2024 10:50:25 +0200 Subject: [PATCH 33/38] OapsProfileIsft remove default values and fix tests --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 4 +- .../plugins/aps/openAPS/APSResultObject.kt | 2 + .../core/interfaces/aps/OapsProfileAutoIsf.kt | 51 +++++++++---------- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 2 - .../OpenAPSAutoISFPluginTest.kt | 4 -- 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index 61a3a014c38..e10a6d535a0 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -710,8 +710,6 @@ class ReplayApsResultsTest @Inject constructor() { autosens_max = determineBasalResult.profile.getDouble("autosens_max"), out_units = determineBasalResult.profile.optString("out_units"), variable_sens = varSens, // TODO only available in result.variableSens? , not in determineBasalResult.profile.getDouble("variable_sens"), - insulinDivisor = 0, - TDD = 0.0, autoISF_version = determineBasalResult.profile.optString("autoISF_version"), enable_autoISF = determineBasalResult.profile.getBoolean("enable_autoISF"), autoISF_max = determineBasalResult.profile.getDouble("autoISF_max"), @@ -772,7 +770,7 @@ class ReplayApsResultsTest @Inject constructor() { aapsLogger.debug(LTag.APS, "File: $filename") // // assertThat(resultKt.reason.toString()).isEqualTo(result?.json?.getString("reason")) assertThat(resultKt.tick ?: "").isEqualTo(result?.json()?.optString("tick")) - assertThat(resultKt.eventualBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("eventualBG")) + assertThat(resultKt.eventualBG ?: 0.0).isWithin(1.0).of(result?.json()?.optDouble("eventualBG") ?:0.0) assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("targetBG")) assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result?.json()?.optDouble("insulinReq")) assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) diff --git a/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPS/APSResultObject.kt b/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPS/APSResultObject.kt index 8b6bd7412ff..7ace3dea5a2 100644 --- a/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPS/APSResultObject.kt +++ b/app/src/androidTest/kotlin/app/aaps/plugins/aps/openAPS/APSResultObject.kt @@ -12,6 +12,7 @@ import app.aaps.core.interfaces.aps.GlucoseStatus import app.aaps.core.interfaces.aps.IobTotal import app.aaps.core.interfaces.aps.MealData import app.aaps.core.interfaces.aps.OapsProfile +import app.aaps.core.interfaces.aps.OapsProfileAutoIsf import app.aaps.core.interfaces.aps.Predictions import app.aaps.core.interfaces.constraints.Constraint import app.aaps.core.interfaces.constraints.ConstraintsChecker @@ -82,6 +83,7 @@ open class APSResultObject(protected val injector: HasAndroidInjector) : APSResu override var glucoseStatus: GlucoseStatus? = null override var currentTemp: CurrentTemp? = null override var oapsProfile: OapsProfile? = null + override var oapsProfileAutoIsf: OapsProfileAutoIsf? = null override var mealData: MealData? = null override var autosensResult: AutosensResult? = null diff --git a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt index 2e7523eee33..69f5e97b61c 100644 --- a/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt +++ b/core/interfaces/src/main/kotlin/app/aaps/core/interfaces/aps/OapsProfileAutoIsf.kt @@ -44,32 +44,29 @@ data class OapsProfileAutoIsf( var autosens_max: Double, var out_units: String, var lgsThreshold: Int?, - //DynISF only - var variable_sens: Double, - var insulinDivisor: Int, - var TDD: Double, //AutoISF only - var autoISF_version: String = "", - var enable_autoISF: Boolean = true, - var autoISF_max: Double = 1.0, - var autoISF_min: Double = 1.0, - var bgAccel_ISF_weight: Double = 0.0, - var bgBrake_ISF_weight: Double = 0.0, - var enable_pp_ISF_always: Boolean = false, - var pp_ISF_hours: Int = 3, - var pp_ISF_weight: Double = 0.0, - var delta_ISFrange_weight: Double = 0.0, - var lower_ISFrange_weight: Double = 0.0, - var higher_ISFrange_weight: Double = 0.0, - var enable_dura_ISF_with_COB: Boolean = false, - var dura_ISF_weight: Double = 0.0, - var smb_delivery_ratio: Double = 0.5, - var smb_delivery_ratio_min: Double = 0.5, - var smb_delivery_ratio_max: Double = 0.5, - var smb_delivery_ratio_bg_range: Double = 0.0, - var smb_max_range_extension: Double = 1.0, - var enableSMB_EvenOn_OddOff: Boolean = false, - var enableSMB_EvenOn_OddOff_always: Boolean = false, - var iob_threshold_percent: Int = 100, - var profile_percentage: Int = 100 + var variable_sens: Double, + var autoISF_version: String, + var enable_autoISF: Boolean, + var autoISF_max: Double, + var autoISF_min: Double, + var bgAccel_ISF_weight: Double, + var bgBrake_ISF_weight: Double, + var enable_pp_ISF_always: Boolean, + var pp_ISF_hours: Int, + var pp_ISF_weight: Double, + var delta_ISFrange_weight: Double, + var lower_ISFrange_weight: Double, + var higher_ISFrange_weight: Double, + var enable_dura_ISF_with_COB: Boolean, + var dura_ISF_weight: Double, + var smb_delivery_ratio: Double, + var smb_delivery_ratio_min: Double, + var smb_delivery_ratio_max: Double, + var smb_delivery_ratio_bg_range: Double, + var smb_max_range_extension: Double, + var enableSMB_EvenOn_OddOff: Boolean, + var enableSMB_EvenOn_OddOff_always: Boolean, + var iob_threshold_percent: Int, + var profile_percentage: Int ) \ No newline at end of file diff --git a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt index b5e513c764a..82d2820cb9d 100644 --- a/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt +++ b/plugins/aps/src/main/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPlugin.kt @@ -334,8 +334,6 @@ open class OpenAPSAutoISFPlugin @Inject constructor( autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = if (profileFunction.getUnits() == GlucoseUnit.MMOL) "mmol/L" else "mg/dl", variable_sens = variableSensitivity, - insulinDivisor = 0, - TDD = 0.0, autoISF_version = autoIsfVersion, enable_autoISF = autoIsfWeights, autoISF_max = autoISF_max, diff --git a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt index 599960a3598..2478b9060a6 100644 --- a/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt +++ b/plugins/aps/src/test/kotlin/app/aaps/plugins/aps/openAPSAutoISF/OpenAPSAutoISFPluginTest.kt @@ -183,8 +183,6 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = "mg/dl", variable_sens = 111.1, - insulinDivisor = 0, - TDD = 0.0, autoISF_version = "3.0", enable_autoISF = true, autoISF_max = 1.5, @@ -272,8 +270,6 @@ class OpenAPSAutoISFPluginTest : TestBaseWithProfile() { autosens_max = preferences.get(DoubleKey.AutosensMax), out_units = "mg/dl", variable_sens = 47.11, - insulinDivisor = 0, - TDD = 0.0, autoISF_version = "3.0", enable_autoISF = false, autoISF_max = 1.5, From baa2c5d0ebad4b27d8adc8d9069c2f3ba2146755 Mon Sep 17 00:00:00 2001 From: Philoul Date: Wed, 8 May 2024 10:52:53 +0200 Subject: [PATCH 34/38] Clean code --- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt index e10a6d535a0..10c9e251146 100644 --- a/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt +++ b/app/src/androidTest/kotlin/app/aaps/ReplayApsResultsTest.kt @@ -769,19 +769,19 @@ class ReplayApsResultsTest @Inject constructor() { // aapsLogger.debug(LTag.APS, resultKt.reason.toString()) aapsLogger.debug(LTag.APS, "File: $filename") // // assertThat(resultKt.reason.toString()).isEqualTo(result?.json?.getString("reason")) - assertThat(resultKt.tick ?: "").isEqualTo(result?.json()?.optString("tick")) - assertThat(resultKt.eventualBG ?: 0.0).isWithin(1.0).of(result?.json()?.optDouble("eventualBG") ?:0.0) - assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result?.json()?.optDouble("targetBG")) - assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result?.json()?.optDouble("insulinReq")) - assertThat(resultKt.carbsReq ?: 0).isEqualTo(result?.json()?.optInt("carbsReq")) - assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result?.json()?.optInt("carbsReqWithin")) - assertThat(resultKt.units ?: Double.NaN).isEqualTo(result?.json()?.optDouble("units")) - assertThat(resultKt.sensitivityRatio ?: Double.NaN).isEqualTo(result?.json()?.optDouble("sensitivityRatio")) - assertThat(resultKt.duration ?: 0).isEqualTo(result?.json()?.optInt("duration")) - assertThat(resultKt.rate ?: Double.NaN).isEqualTo(result?.json()?.optDouble("rate")) - assertThat(resultKt.COB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("COB")) - assertThat(resultKt.IOB ?: Double.NaN).isEqualTo(result?.json()?.optDouble("IOB")) - assertThat(resultKt.variable_sens ?: Double.NaN).isEqualTo(result?.json()?.optDouble("variable_sens")) + assertThat(resultKt.tick ?: "").isEqualTo(result.json()?.optString("tick")) + assertThat(resultKt.eventualBG ?: 0.0).isWithin(1.0).of(result.json()?.optDouble("eventualBG") ?: 0.0) + assertThat(resultKt.targetBG ?: Double.NaN).isEqualTo(result.json()?.optDouble("targetBG")) + assertThat(resultKt.insulinReq ?: Double.NaN).isEqualTo(result.json()?.optDouble("insulinReq")) + assertThat(resultKt.carbsReq ?: 0).isEqualTo(result.json()?.optInt("carbsReq")) + assertThat(resultKt.carbsReqWithin ?: 0).isEqualTo(result.json()?.optInt("carbsReqWithin")) + assertThat(resultKt.units ?: Double.NaN).isEqualTo(result.json()?.optDouble("units")) + assertThat(resultKt.sensitivityRatio ?: Double.NaN).isEqualTo(result.json()?.optDouble("sensitivityRatio")) + assertThat(resultKt.duration ?: 0).isEqualTo(result.json()?.optInt("duration")) + assertThat(resultKt.rate ?: Double.NaN).isEqualTo(result.json()?.optDouble("rate")) + assertThat(resultKt.COB ?: Double.NaN).isEqualTo(result.json()?.optDouble("COB")) + assertThat(resultKt.IOB ?: Double.NaN).isEqualTo(result.json()?.optDouble("IOB")) + assertThat(resultKt.variable_sens ?: Double.NaN).isEqualTo(result.json()?.optDouble("variable_sens")) } enum class TestSource { ASSET, FILE } From cd49485575f1642deea02d90a93d2de5c459be7c Mon Sep 17 00:00:00 2001 From: ga-zelle Date: Sat, 20 Jul 2024 02:49:08 +0200 Subject: [PATCH 35/38] first try of AutoISF 3.0.1 --- .idea/codeStyles/Project.xml | 2 +- .../OpenAPSSMBAutoISF/determine-basal.js | 172 +++++++-------- .../assets/results/2024-01-05_111248.json | 2 +- .../kotlin/app/aaps/ReplayApsResultsTest.kt | 5 - .../DetermineBasalAdapterAutoISFJS.kt | 14 +- .../core/interfaces/aps/OapsProfileAutoIsf.kt | 10 +- .../kotlin/app/aaps/core/keys/BooleanKey.kt | 8 +- .../kotlin/app/aaps/core/keys/DoubleKey.kt | 2 +- .../main/kotlin/app/aaps/core/keys/IntKey.kt | 2 +- core/keys/src/main/res/values/keys.xml | 8 +- .../openAPSAutoISF/OpenAPSAutoISFPlugin.kt | 199 +++++++----------- plugins/aps/src/main/res/values/strings.xml | 24 ++- .../OpenAPSAutoISFPluginTest.kt | 18 +- 13 files changed, 206 insertions(+), 260 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 3f1a6ad5064..680e62e6652 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,7 +1,7 @@