AutotunePlugin -> plugins module

This commit is contained in:
Milos Kozak 2022-11-04 20:43:11 +01:00
parent efcae9f073
commit f0f5a89fe6
37 changed files with 403 additions and 348 deletions

View file

@ -37,13 +37,11 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.OpenAPSSMBDyn
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
import info.nightscout.androidaps.plugins.general.autotune.AutotunePlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
import info.nightscout.androidaps.plugins.general.wear.WearPlugin import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.plugins.general.xdripStatusline.StatusLinePlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
@ -67,7 +65,9 @@ import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionTyp
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.CUSTOM_PIN import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.CUSTOM_PIN
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.NONE import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.NONE
import info.nightscout.automation.AutomationPlugin import info.nightscout.automation.AutomationPlugin
import info.nightscout.plugins.general.autotune.AutotunePlugin
import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.plugins.general.xdripStatusline.StatusLinePlugin
import info.nightscout.plugins.insulin.InsulinOrefFreePeakPlugin import info.nightscout.plugins.insulin.InsulinOrefFreePeakPlugin
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
@ -405,7 +405,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
} else { } else {
if (pref.key.contains("pin")) { if (pref.key.contains("pin")) {
pref.summary = rh.gs(R.string.pin_not_set) pref.summary = rh.gs(R.string.pin_not_set)
}else { } else {
pref.summary = rh.gs(R.string.password_not_set) pref.summary = rh.gs(R.string.password_not_set)
} }
} }

View file

@ -11,7 +11,6 @@ import info.nightscout.androidaps.dana.di.DanaModule
import info.nightscout.androidaps.danar.di.DanaRModule import info.nightscout.androidaps.danar.di.DanaRModule
import info.nightscout.androidaps.danars.di.DanaRSModule import info.nightscout.androidaps.danars.di.DanaRSModule
import info.nightscout.androidaps.database.DatabaseModule import info.nightscout.androidaps.database.DatabaseModule
import info.nightscout.androidaps.dependencyInjection.AutotuneModule
import info.nightscout.androidaps.diaconn.di.DiaconnG8Module import info.nightscout.androidaps.diaconn.di.DiaconnG8Module
import info.nightscout.androidaps.insight.di.InsightDatabaseModule import info.nightscout.androidaps.insight.di.InsightDatabaseModule
import info.nightscout.androidaps.insight.di.InsightModule import info.nightscout.androidaps.insight.di.InsightModule
@ -40,7 +39,6 @@ import javax.inject.Singleton
FragmentsModule::class, FragmentsModule::class,
ReceiversModule::class, ReceiversModule::class,
ServicesModule::class, ServicesModule::class,
AutotuneModule::class,
ObjectivesModule::class, ObjectivesModule::class,
WizardModule::class, WizardModule::class,
APSModule::class, APSModule::class,

View file

@ -42,7 +42,6 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImpl import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImpl
import info.nightscout.androidaps.plugins.general.autotune.AutotunePlugin
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
@ -71,6 +70,7 @@ import info.nightscout.implementation.queue.CommandQueueImplementation
import info.nightscout.implementation.stats.DexcomTirCalculatorImpl import info.nightscout.implementation.stats.DexcomTirCalculatorImpl
import info.nightscout.implementation.stats.TddCalculatorImpl import info.nightscout.implementation.stats.TddCalculatorImpl
import info.nightscout.implementation.stats.TirCalculatorImpl import info.nightscout.implementation.stats.TirCalculatorImpl
import info.nightscout.plugins.general.autotune.AutotunePlugin
import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP

View file

@ -27,17 +27,16 @@ import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment
import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
import info.nightscout.androidaps.plugins.general.actions.ActionsFragment import info.nightscout.androidaps.plugins.general.actions.ActionsFragment
import info.nightscout.androidaps.plugins.general.autotune.AutotuneFragment
import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment
import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment import info.nightscout.androidaps.plugins.general.overview.OverviewFragment
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
import info.nightscout.androidaps.plugins.general.wear.WearFragment import info.nightscout.androidaps.plugins.general.wear.WearFragment
import info.nightscout.plugins.profile.ProfileFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.utils.protection.PasswordCheck import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.plugins.general.autotune.AutotuneFragment
@Module @Module
@Suppress("unused") @Suppress("unused")
@ -48,10 +47,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesActionsFragment(): ActionsFragment @ContributesAndroidInjector abstract fun contributesActionsFragment(): ActionsFragment
@ContributesAndroidInjector abstract fun contributesAutotuneFragment(): AutotuneFragment @ContributesAndroidInjector abstract fun contributesAutotuneFragment(): AutotuneFragment
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment @ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
@ContributesAndroidInjector abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment @ContributesAndroidInjector abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): ProfileFragment
@ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment @ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment
@ContributesAndroidInjector abstract fun contributesOpenAPSFragment(): OpenAPSFragment @ContributesAndroidInjector abstract fun contributesOpenAPSFragment(): OpenAPSFragment
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment @ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment

View file

@ -24,18 +24,14 @@ import info.nightscout.androidaps.plugins.constraints.signatureVerifier.Signatur
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerPlugin import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerPlugin
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
import info.nightscout.androidaps.plugins.general.autotune.AutotunePlugin
import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin
import info.nightscout.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
import info.nightscout.plugins.general.themes.ThemeSwitcherPlugin
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin
import info.nightscout.androidaps.plugins.general.wear.WearPlugin import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin import info.nightscout.androidaps.plugins.pump.eopatch.EopatchPumpPlugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
@ -58,12 +54,16 @@ import info.nightscout.androidaps.plugins.source.RandomBgPlugin
import info.nightscout.androidaps.plugins.source.TomatoPlugin import info.nightscout.androidaps.plugins.source.TomatoPlugin
import info.nightscout.androidaps.plugins.source.XdripPlugin import info.nightscout.androidaps.plugins.source.XdripPlugin
import info.nightscout.automation.AutomationPlugin import info.nightscout.automation.AutomationPlugin
import info.nightscout.plugins.general.autotune.AutotunePlugin
import info.nightscout.plugins.general.food.FoodPlugin
import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.plugins.general.themes.ThemeSwitcherPlugin
import info.nightscout.plugins.general.xdripStatusline.StatusLinePlugin import info.nightscout.plugins.general.xdripStatusline.StatusLinePlugin
import info.nightscout.plugins.insulin.InsulinLyumjevPlugin import info.nightscout.plugins.insulin.InsulinLyumjevPlugin
import info.nightscout.plugins.insulin.InsulinOrefFreePeakPlugin import info.nightscout.plugins.insulin.InsulinOrefFreePeakPlugin
import info.nightscout.plugins.insulin.InsulinOrefRapidActingPlugin import info.nightscout.plugins.insulin.InsulinOrefRapidActingPlugin
import info.nightscout.plugins.insulin.InsulinOrefUltraRapidActingPlugin import info.nightscout.plugins.insulin.InsulinOrefUltraRapidActingPlugin
import info.nightscout.plugins.profile.ProfilePlugin
import javax.inject.Qualifier import javax.inject.Qualifier
@Suppress("unused") @Suppress("unused")

View file

@ -7,17 +7,23 @@ import androidx.core.content.FileProvider
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.plugins.general.maintenance.LoggerUtils
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import java.io.* import java.io.BufferedInputStream
import java.util.* import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.Arrays
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import javax.inject.Inject import javax.inject.Inject

View file

@ -51,7 +51,6 @@ import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.floor
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -450,23 +449,6 @@ class IobCobCalculatorPlugin @Inject constructor(
return array return array
} }
companion object {
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
fun percentile(arr: Array<Double>, p: Double): Double {
if (arr.isEmpty()) return 0.0
if (p <= 0) return arr[0]
if (p >= 1) return arr[arr.size - 1]
val index = arr.size * p
val lower = floor(index)
val upper = lower + 1
val weight = index % 1
return if (upper >= arr.size) arr[lower.toInt()] else arr[lower.toInt()] * (1 - weight) + arr[upper.toInt()] * weight
}
}
/** /**
* Time range to the past for IOB calculation * Time range to the past for IOB calculation
* @return milliseconds * @return milliseconds

View file

@ -12,18 +12,18 @@ import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.plugins.utils.Percentile
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.Arrays
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -116,7 +116,7 @@ class SensitivityAAPSPlugin @Inject constructor(
val sensResult: String val sensResult: String
aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity") aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity")
Arrays.sort(deviations) Arrays.sort(deviations)
val percentile = IobCobCalculatorPlugin.percentile(deviations, 0.50) val percentile = Percentile.percentile(deviations, 0.50)
val basalOff = percentile * (60.0 / 5.0) / sens val basalOff = percentile * (60.0 / 5.0) / sens
val ratio = 1 + basalOff / profile.getMaxDailyBasal() val ratio = 1 + basalOff / profile.getMaxDailyBasal()
sensResult = when { sensResult = when {
@ -126,13 +126,16 @@ class SensitivityAAPSPlugin @Inject constructor(
} }
aapsLogger.debug(LTag.AUTOSENS, sensResult) aapsLogger.debug(LTag.AUTOSENS, sensResult)
val output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit, val output = fillResult(
sensResult, deviationsArray.size) ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, deviationsArray.size
)
aapsLogger.debug( aapsLogger.debug(
LTag.AUTOSENS, "Sensitivity to: " LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) + + dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio " ratio: " + output.ratio
+ " mealCOB: " + current.cob) + " mealCOB: " + current.cob
)
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: deviations " + deviations.contentToString()) aapsLogger.debug(LTag.AUTOSENS, "Sensitivity to: deviations " + deviations.contentToString())
return output return output
} }
@ -158,7 +161,10 @@ class SensitivityAAPSPlugin @Inject constructor(
override fun applyConfiguration(configuration: JSONObject) { override fun applyConfiguration(configuration: JSONObject) {
try { try {
if (configuration.has(rh.gs(R.string.key_absorption_maxtime))) sp.putDouble(R.string.key_absorption_maxtime, configuration.getDouble(rh.gs(R.string.key_absorption_maxtime))) if (configuration.has(rh.gs(R.string.key_absorption_maxtime))) sp.putDouble(R.string.key_absorption_maxtime, configuration.getDouble(rh.gs(R.string.key_absorption_maxtime)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(R.string.key_openapsama_autosens_period, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_period))) if (configuration.has(rh.gs(R.string.key_openapsama_autosens_period))) sp.putDouble(
R.string.key_openapsama_autosens_period,
configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_period))
)
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_max))) if (configuration.has(rh.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_min))) if (configuration.has(rh.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_min)))
} catch (e: JSONException) { } catch (e: JSONException) {

View file

@ -12,19 +12,19 @@ import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType import info.nightscout.androidaps.interfaces.Sensitivity.SensitivityType
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.plugins.utils.Percentile
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.Arrays
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -75,7 +75,7 @@ class SensitivityOref1Plugin @Inject constructor(
//[0] = 8 hour //[0] = 8 hour
//[1] = 24 hour //[1] = 24 hour
//deviationsHour has DeviationsArray //deviationsHour has DeviationsArray
val deviationsHour = mutableListOf(ArrayList<Double>(), ArrayList<Double>()) val deviationsHour = mutableListOf(ArrayList(), ArrayList<Double>())
val pastSensitivityArray = mutableListOf("", "") val pastSensitivityArray = mutableListOf("", "")
val sensResultArray = mutableListOf("", "") val sensResultArray = mutableListOf("", "")
val ratioArray = mutableListOf(0.0, 0.0) val ratioArray = mutableListOf(0.0, 0.0)
@ -160,8 +160,8 @@ class SensitivityOref1Plugin @Inject constructor(
val sens = profile.getIsfMgdl() val sens = profile.getIsfMgdl()
aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity") aapsLogger.debug(LTag.AUTOSENS, "Records: $index $pastSensitivity")
Arrays.sort(deviations) Arrays.sort(deviations)
val pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50) val pSensitive = Percentile.percentile(deviations, 0.50)
val pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.50) val pResistant = Percentile.percentile(deviations, 0.50)
var basalOff = 0.0 var basalOff = 0.0
when { when {
pSensitive < 0 -> { // sensitive pSensitive < 0 -> { // sensitive
@ -198,7 +198,8 @@ class SensitivityOref1Plugin @Inject constructor(
LTag.AUTOSENS, "Sensitivity to: " LTag.AUTOSENS, "Sensitivity to: "
+ dateUtil.dateAndTimeString(toTime) + + dateUtil.dateAndTimeString(toTime) +
" ratio: " + output.ratio " ratio: " + output.ratio
+ " mealCOB: " + current.cob) + " mealCOB: " + current.cob
)
return output return output
} }
@ -219,7 +220,10 @@ class SensitivityOref1Plugin @Inject constructor(
override fun applyConfiguration(configuration: JSONObject) { override fun applyConfiguration(configuration: JSONObject) {
try { try {
if (configuration.has(rh.gs(R.string.key_openapsama_min_5m_carbimpact))) sp.putDouble(R.string.key_openapsama_min_5m_carbimpact, configuration.getDouble(rh.gs(R.string.key_openapsama_min_5m_carbimpact))) if (configuration.has(rh.gs(R.string.key_openapsama_min_5m_carbimpact))) sp.putDouble(
R.string.key_openapsama_min_5m_carbimpact,
configuration.getDouble(rh.gs(R.string.key_openapsama_min_5m_carbimpact))
)
if (configuration.has(rh.gs(R.string.key_absorption_cutoff))) sp.putDouble(R.string.key_absorption_cutoff, configuration.getDouble(rh.gs(R.string.key_absorption_cutoff))) if (configuration.has(rh.gs(R.string.key_absorption_cutoff))) sp.putDouble(R.string.key_absorption_cutoff, configuration.getDouble(rh.gs(R.string.key_absorption_cutoff)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_max))) if (configuration.has(rh.gs(R.string.key_openapsama_autosens_max))) sp.getDouble(R.string.key_openapsama_autosens_max, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_max)))
if (configuration.has(rh.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_min))) if (configuration.has(rh.gs(R.string.key_openapsama_autosens_min))) sp.getDouble(R.string.key_openapsama_autosens_min, configuration.getDouble(rh.gs(R.string.key_openapsama_autosens_min)))

View file

@ -270,8 +270,6 @@
<string name="show_queue">Show queue</string> <string name="show_queue">Show queue</string>
<string name="queue">Queue:</string> <string name="queue">Queue:</string>
<string name="status">Status:</string> <string name="status">Status:</string>
<string name="key_nsclientinternal_url" translatable="false">nsclientinternal_url</string>
<string name="key_nsclientinternal_api_secret" translatable="false">nsclientinternal_api_secret</string>
<string name="clearlog">Clear log</string> <string name="clearlog">Clear log</string>
<string name="key_nsclientinternal_autoscroll" translatable="false">nsclientinternal_autoscroll</string> <string name="key_nsclientinternal_autoscroll" translatable="false">nsclientinternal_autoscroll</string>
<string name="key_nsclientinternal_paused" translatable="false">nsclientinternal_paused</string> <string name="key_nsclientinternal_paused" translatable="false">nsclientinternal_paused</string>
@ -529,7 +527,6 @@
<string name="overview_show_basals">Basals</string> <string name="overview_show_basals">Basals</string>
<string name="closed_loop_disabled_on_dev_branch">Running dev version. Closed loop is disabled.</string> <string name="closed_loop_disabled_on_dev_branch">Running dev version. Closed loop is disabled.</string>
<string name="engineering_mode_enabled">Engineering mode enabled</string> <string name="engineering_mode_enabled">Engineering mode enabled</string>
<string name="profileswitch_ismissing">ProfileSwitch missing. Please do a profile switch or press \"Activate Profile\" in the LocalProfile.</string>
<string name="pumpisnottempbasalcapable">Pump is not temp basal capable</string> <string name="pumpisnottempbasalcapable">Pump is not temp basal capable</string>
<string name="closedmodedisabledinpreferences">Closed loop mode disabled in preferences</string> <string name="closedmodedisabledinpreferences">Closed loop mode disabled in preferences</string>
<string name="autosensdisabledinpreferences">Autosens disabled in preferences</string> <string name="autosensdisabledinpreferences">Autosens disabled in preferences</string>

View file

@ -3,10 +3,11 @@ package info.nightscout.androidaps.plugins.general.maintenance
import android.content.Context import android.content.Context
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.interfaces.BuildHelper import info.nightscout.androidaps.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.plugins.general.maintenance.LoggerUtils
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
@ -27,7 +28,7 @@ class MaintenancePluginTest : TestBase() {
@Mock lateinit var fileListProvider: PrefFileListProvider @Mock lateinit var fileListProvider: PrefFileListProvider
@Mock lateinit var config: Config @Mock lateinit var config: Config
lateinit var sut: MaintenancePlugin private lateinit var sut: MaintenancePlugin
@Before @Before
fun mock() { fun mock() {

View file

@ -86,6 +86,8 @@
<string name="key_rangetodisplay" translatable="false">rangetodisplay</string> <string name="key_rangetodisplay" translatable="false">rangetodisplay</string>
<string name="key_local_profile_last_change" translatable="false">local_profile_last_change</string> <string name="key_local_profile_last_change" translatable="false">local_profile_last_change</string>
<string name="key_ns_receive_profile_store" translatable="false">ns_receive_profile_store</string> <string name="key_ns_receive_profile_store" translatable="false">ns_receive_profile_store</string>
<string name="key_nsclientinternal_url" translatable="false">nsclientinternal_url</string>
<string name="key_nsclientinternal_api_secret" translatable="false">nsclientinternal_api_secret</string>
<!-- General--> <!-- General-->
<string name="refresh">Refresh</string> <string name="refresh">Refresh</string>
@ -233,6 +235,8 @@
<string name="remove_label">REMOVE</string> <string name="remove_label">REMOVE</string>
<string name="activate_profile">Activate profile</string> <string name="activate_profile">Activate profile</string>
<string name="reset">reset</string> <string name="reset">reset</string>
<string name="profileswitch_ismissing">ProfileSwitch missing. Please do a profile switch or press \"Activate Profile\" in the LocalProfile.</string>
<string name="profile">Profile</string>
<!-- Constraints--> <!-- Constraints-->
<string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string> <string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string>

View file

@ -1,12 +1,15 @@
package info.nightscout.androidaps.dependencyInjection package info.nightscout.plugins.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.autotune.AutotuneCore import info.nightscout.plugins.general.autotune.AutotuneCore
import info.nightscout.androidaps.plugins.general.autotune.AutotuneIob import info.nightscout.plugins.general.autotune.AutotuneFS
import info.nightscout.androidaps.plugins.general.autotune.AutotunePrep import info.nightscout.plugins.general.autotune.AutotuneIob
import info.nightscout.androidaps.plugins.general.autotune.AutotuneFS import info.nightscout.plugins.general.autotune.AutotunePrep
import info.nightscout.androidaps.plugins.general.autotune.data.* import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.BGDatum
import info.nightscout.plugins.general.autotune.data.CRDatum
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
@Module @Module
@Suppress("unused") @Suppress("unused")

View file

@ -6,7 +6,9 @@ import dagger.Module
includes = [ includes = [
InsulinModule::class, InsulinModule::class,
FoodModule::class, FoodModule::class,
SMSCommunicatorModule::class SMSCommunicatorModule::class,
AutotuneModule::class,
ProfileModule::class
] ]
) )

View file

@ -0,0 +1,12 @@
package info.nightscout.plugins.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.plugins.profile.ProfileFragment
@Module
@Suppress("unused")
abstract class ProfileModule {
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): ProfileFragment
}

View file

@ -1,15 +1,16 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.plugins.R
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.plugins.utils.Percentile
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.max
@Singleton @Singleton
class AutotuneCore @Inject constructor( class AutotuneCore @Inject constructor(
@ -47,8 +48,7 @@ class AutotuneCore @Inject constructor(
// tune DIA // tune DIA
var newDia = dia var newDia = dia
if (diaDeviations.size > 0) if (diaDeviations.isNotEmpty()) {
{
val currentDiaMeanDev = diaDeviations[2].meanDeviation val currentDiaMeanDev = diaDeviations[2].meanDeviation
val currentDiaRMSDev = diaDeviations[2].rmsDeviation val currentDiaRMSDev = diaDeviations[2].rmsDeviation
//Console.WriteLine(DIA,currentDIAMeanDev,currentDIARMSDev); //Console.WriteLine(DIA,currentDIAMeanDev,currentDIARMSDev);
@ -56,35 +56,28 @@ class AutotuneCore @Inject constructor(
var minRmsDeviations = 1000000.0 var minRmsDeviations = 1000000.0
var meanBest = 2 var meanBest = 2
var rmsBest = 2 var rmsBest = 2
for (i in 0..diaDeviations.size-1) for (i in diaDeviations.indices) {
{
val meanDeviations = diaDeviations[i].meanDeviation val meanDeviations = diaDeviations[i].meanDeviation
val rmsDeviations = diaDeviations[i].rmsDeviation val rmsDeviations = diaDeviations[i].rmsDeviation
if (meanDeviations < minMeanDeviations) if (meanDeviations < minMeanDeviations) {
{
minMeanDeviations = Round.roundTo(meanDeviations, 0.001) minMeanDeviations = Round.roundTo(meanDeviations, 0.001)
meanBest = i meanBest = i
} }
if (rmsDeviations < minRmsDeviations) if (rmsDeviations < minRmsDeviations) {
{
minRmsDeviations = Round.roundTo(rmsDeviations, 0.001) minRmsDeviations = Round.roundTo(rmsDeviations, 0.001)
rmsBest = i rmsBest = i
} }
} }
log("Best insulinEndTime for meanDeviations: ${diaDeviations[meanBest].dia} hours") log("Best insulinEndTime for meanDeviations: ${diaDeviations[meanBest].dia} hours")
log("Best insulinEndTime for RMSDeviations: ${diaDeviations[rmsBest].dia} hours") log("Best insulinEndTime for RMSDeviations: ${diaDeviations[rmsBest].dia} hours")
if (meanBest < 2 && rmsBest < 2) if (meanBest < 2 && rmsBest < 2) {
{
if (diaDeviations[1].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[1].rmsDeviation < currentDiaRMSDev * 0.99) if (diaDeviations[1].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[1].rmsDeviation < currentDiaRMSDev * 0.99)
newDia = diaDeviations[1].dia newDia = diaDeviations[1].dia
} } else if (meanBest > 2 && rmsBest > 2) {
else if (meanBest > 2 && rmsBest > 2)
{
if (diaDeviations[3].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[3].rmsDeviation < currentDiaRMSDev * 0.99) if (diaDeviations[3].meanDeviation < currentDiaMeanDev * 0.99 && diaDeviations[3].rmsDeviation < currentDiaRMSDev * 0.99)
newDia = diaDeviations[3].dia newDia = diaDeviations[3].dia
} }
if (newDia > 12.0) if (newDia > 12.0) {
{
log("insulinEndTime maximum is 12h: not raising further") log("insulinEndTime maximum is 12h: not raising further")
newDia = 12.0 newDia = 12.0
} }
@ -96,8 +89,7 @@ class AutotuneCore @Inject constructor(
// tune insulinPeakTime // tune insulinPeakTime
var newPeak = peak var newPeak = peak
if (peakDeviations.size > 2) if (peakDeviations.size > 2) {
{
val currentPeakMeanDev = peakDeviations[2].meanDeviation val currentPeakMeanDev = peakDeviations[2].meanDeviation
val currentPeakRMSDev = peakDeviations[2].rmsDeviation val currentPeakRMSDev = peakDeviations[2].rmsDeviation
//Console.WriteLine(currentPeakMeanDev); //Console.WriteLine(currentPeakMeanDev);
@ -105,37 +97,31 @@ class AutotuneCore @Inject constructor(
var minRmsDeviations = 1000000.0 var minRmsDeviations = 1000000.0
var meanBest = 2 var meanBest = 2
var rmsBest = 2 var rmsBest = 2
for (i in 0..peakDeviations.size-1) for (i in peakDeviations.indices) {
{ val meanDeviations = peakDeviations[i].meanDeviation
val meanDeviations = peakDeviations[i].meanDeviation; val rmsDeviations = peakDeviations[i].rmsDeviation
val rmsDeviations = peakDeviations[i].rmsDeviation; if (meanDeviations < minMeanDeviations) {
if (meanDeviations < minMeanDeviations)
{
minMeanDeviations = Round.roundTo(meanDeviations, 0.001) minMeanDeviations = Round.roundTo(meanDeviations, 0.001)
meanBest = i meanBest = i
} }
if (rmsDeviations < minRmsDeviations) if (rmsDeviations < minRmsDeviations) {
{
minRmsDeviations = Round.roundTo(rmsDeviations, 0.001) minRmsDeviations = Round.roundTo(rmsDeviations, 0.001)
rmsBest = i rmsBest = i
} }
} }
log("Best insulinPeakTime for meanDeviations: ${peakDeviations[meanBest].peak} minutes") log("Best insulinPeakTime for meanDeviations: ${peakDeviations[meanBest].peak} minutes")
log("Best insulinPeakTime for RMSDeviations: ${peakDeviations[rmsBest].peak} minutes") log("Best insulinPeakTime for RMSDeviations: ${peakDeviations[rmsBest].peak} minutes")
if (meanBest < 2 && rmsBest < 2) if (meanBest < 2 && rmsBest < 2) {
{
if (peakDeviations[1].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[1].rmsDeviation < currentPeakRMSDev * 0.99) if (peakDeviations[1].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[1].rmsDeviation < currentPeakRMSDev * 0.99)
newPeak = peakDeviations[1].peak newPeak = peakDeviations[1].peak
} } else if (meanBest > 2 && rmsBest > 2) {
else if (meanBest > 2 && rmsBest > 2)
{
if (peakDeviations[3].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[3].rmsDeviation < currentPeakRMSDev * 0.99) if (peakDeviations[3].meanDeviation < currentPeakMeanDev * 0.99 && peakDeviations[3].rmsDeviation < currentPeakRMSDev * 0.99)
newPeak = peakDeviations[3].peak newPeak = peakDeviations[3].peak
} }
if (newPeak != peak) if (newPeak != peak)
log("Adjusting insulinPeakTime from " + peak + " to " + newPeak + " minutes") log("Adjusting insulinPeakTime from $peak to $newPeak minutes")
else else
log("Leaving insulinPeakTime unchanged at " + peak) log("Leaving insulinPeakTime unchanged at $peak")
} }
// Calculate carb ratio (CR) independently of csf and isf // Calculate carb ratio (CR) independently of csf and isf
@ -180,22 +166,22 @@ class AutotuneCore @Inject constructor(
for (i in 0..23) { for (i in 0..23) {
newHourlyBasalProfile[i] = hourlyBasalProfile[i] newHourlyBasalProfile[i] = hourlyBasalProfile[i]
} }
val basalUntuned = previousAutotune.basalUntuned val basalUnTuned = previousAutotune.basalUntuned
//autotune-core (lib/autotune/index.js) #210-#266 //autotune-core (lib/autotune/index.js) #210-#266
// look at net deviations for each hour // look at net deviations for each hour
for (hour in 0..23) { for (hour in 0..23) {
var deviations = 0.0 var deviations = 0.0
for (i in basalGlucose.indices) { for (i in basalGlucose.indices) {
val BGTime = Calendar.getInstance() val bgTime = Calendar.getInstance()
//var BGTime: Date? = null //var BGTime: Date? = null
if (basalGlucose[i].date != 0L) { if (basalGlucose[i].date != 0L) {
BGTime.setTimeInMillis(basalGlucose[i].date) bgTime.timeInMillis = basalGlucose[i].date
//BGTime = Date(basalGlucose[i].date) //BGTime = Date(basalGlucose[i].date)
} else { } else {
log("Could not determine last BG time") log("Could not determine last BG time")
} }
val myHour = BGTime.get(Calendar.HOUR_OF_DAY) val myHour = bgTime.get(Calendar.HOUR_OF_DAY)
//val myHour = BGTime!!.hours //val myHour = BGTime!!.hours
if (hour == myHour) { if (hour == myHour) {
//log.debug(basalGlucose[i].deviation); //log.debug(basalGlucose[i].deviation);
@ -280,7 +266,7 @@ class AutotuneCore @Inject constructor(
} }
//log.debug(hour, newHourlyBasalProfile); //log.debug(hour, newHourlyBasalProfile);
newHourlyBasalProfile[hour] = Round.roundTo(0.8 * hourlyBasalProfile[hour] + 0.1 * newHourlyBasalProfile[lastAdjustedHour] + 0.1 * newHourlyBasalProfile[nextAdjustedHour], 0.001) newHourlyBasalProfile[hour] = Round.roundTo(0.8 * hourlyBasalProfile[hour] + 0.1 * newHourlyBasalProfile[lastAdjustedHour] + 0.1 * newHourlyBasalProfile[nextAdjustedHour], 0.001)
basalUntuned[hour]++ basalUnTuned[hour]++
log("Adjusting hour " + hour + " basal from " + hourlyBasalProfile[hour] + " to " + newHourlyBasalProfile[hour] + " based on hour " + lastAdjustedHour + " = " + newHourlyBasalProfile[lastAdjustedHour] + " and hour " + nextAdjustedHour + " = " + newHourlyBasalProfile[nextAdjustedHour]) log("Adjusting hour " + hour + " basal from " + hourlyBasalProfile[hour] + " to " + newHourlyBasalProfile[hour] + " based on hour " + lastAdjustedHour + " = " + newHourlyBasalProfile[lastAdjustedHour] + " and hour " + nextAdjustedHour + " = " + newHourlyBasalProfile[nextAdjustedHour])
} else { } else {
lastAdjustedHour = hour lastAdjustedHour = hour
@ -301,7 +287,6 @@ class AutotuneCore @Inject constructor(
var mealCarbs = 0 var mealCarbs = 0
var totalMealCarbs = 0 var totalMealCarbs = 0
var totalDeviations = 0.0 var totalDeviations = 0.0
val fullNewCSF: Double
//log.debug(CSFGlucose[0].mealAbsorption); //log.debug(CSFGlucose[0].mealAbsorption);
//log.debug(CSFGlucose[0]); //log.debug(CSFGlucose[0]);
//autotune-core (lib/autotune/index.js) #346-#365 //autotune-core (lib/autotune/index.js) #346-#365
@ -321,8 +306,8 @@ class AutotuneCore @Inject constructor(
totalDeviations += deviations totalDeviations += deviations
} else { } else {
//todo Philoul check 0 * min5minCarbImpact ??? //todo Philoul check 0 * min5minCarbImpact ???
deviations += Math.max(0 * min5minCarbImpact, csfGlucose[i].deviation) deviations += max(0 * min5minCarbImpact, csfGlucose[i].deviation)
mealCarbs = Math.max(mealCarbs, csfGlucose[i].mealCarbs) mealCarbs = max(mealCarbs, csfGlucose[i].mealCarbs)
} }
} }
// at midnight, write down the mealcarbs as total meal carbs (to prevent special case of when only one meal and it not finishing absorbing by midnight) // at midnight, write down the mealcarbs as total meal carbs (to prevent special case of when only one meal and it not finishing absorbing by midnight)
@ -334,7 +319,7 @@ class AutotuneCore @Inject constructor(
totalDeviations += deviations totalDeviations += deviations
} }
//log.debug(totalDeviations, totalMealCarbs); //log.debug(totalDeviations, totalMealCarbs);
fullNewCSF = if (totalMealCarbs == 0) { val fullNewCSF: Double = if (totalMealCarbs == 0) {
// if no meals today, csf is unchanged // if no meals today, csf is unchanged
csf csf
} else { } else {
@ -420,22 +405,22 @@ class AutotuneCore @Inject constructor(
for (i in isfGlucose.indices) { for (i in isfGlucose.indices) {
val deviation = isfGlucose[i].deviation val deviation = isfGlucose[i].deviation
isfDeviations.add(deviation) isfDeviations.add(deviation)
val BGI = isfGlucose[i].bgi val bgi = isfGlucose[i].bgi
bGIs.add(BGI) bGIs.add(bgi)
val avgDelta = isfGlucose[i].avgDelta val avgDelta = isfGlucose[i].avgDelta
avgDeltas.add(avgDelta) avgDeltas.add(avgDelta)
val ratio = 1 + deviation / BGI val ratio = 1 + deviation / bgi
//log.debug("Deviation:",deviation,"BGI:",BGI,"avgDelta:",avgDelta,"ratio:",ratio); //log.debug("Deviation:",deviation,"BGI:",BGI,"avgDelta:",avgDelta,"ratio:",ratio);
ratios.add(ratio) ratios.add(ratio)
count++ count++
} }
Collections.sort(avgDeltas) avgDeltas.sort()
Collections.sort(bGIs) bGIs.sort()
Collections.sort(isfDeviations) isfDeviations.sort()
Collections.sort(ratios) ratios.sort()
var p50deviation = IobCobCalculatorPlugin.percentile(isfDeviations.toTypedArray(), 0.50) var p50deviation = Percentile.percentile(isfDeviations.toTypedArray(), 0.50)
var p50BGI = IobCobCalculatorPlugin.percentile(bGIs.toTypedArray(), 0.50) var p50BGI = Percentile.percentile(bGIs.toTypedArray(), 0.50)
val p50ratios = Round.roundTo(IobCobCalculatorPlugin.percentile(ratios.toTypedArray(), 0.50), 0.001) val p50ratios = Round.roundTo(Percentile.percentile(ratios.toTypedArray(), 0.50), 0.001)
var fullNewISF = isf var fullNewISF = isf
if (count < 10) { if (count < 10) {
// leave isf unchanged if fewer than 5 isf data points // leave isf unchanged if fewer than 5 isf data points
@ -446,13 +431,12 @@ class AutotuneCore @Inject constructor(
} }
fullNewISF = Round.roundTo(fullNewISF, 0.001) fullNewISF = Round.roundTo(fullNewISF, 0.001)
// adjust the target isf to be a weighted average of fullNewISF and pumpISF // adjust the target isf to be a weighted average of fullNewISF and pumpISF
val adjustmentFraction: Double
/* /*
// TODO: philoul may be allow adjustmentFraction in settings with safety limits ?) // TODO: philoul may be allow adjustmentFraction in settings with safety limits ?)
if (typeof(pumpProfile.autotune_isf_adjustmentFraction) !== 'undefined') { if (typeof(pumpProfile.autotune_isf_adjustmentFraction) !== 'undefined') {
adjustmentFraction = pumpProfile.autotune_isf_adjustmentFraction; adjustmentFraction = pumpProfile.autotune_isf_adjustmentFraction;
} else {*/ } else {*/
adjustmentFraction = 1.0 val adjustmentFraction = 1.0
// } // }
// low autosens ratio = high isf // low autosens ratio = high isf
@ -501,7 +485,7 @@ class AutotuneCore @Inject constructor(
previousAutotune.basal = basalProfile previousAutotune.basal = basalProfile
previousAutotune.isf = isf previousAutotune.isf = isf
previousAutotune.ic = Round.roundTo(carbRatio, 0.001) previousAutotune.ic = Round.roundTo(carbRatio, 0.001)
previousAutotune.basalUntuned = basalUntuned previousAutotune.basalUntuned = basalUnTuned
previousAutotune.dia = newDia previousAutotune.dia = newDia
previousAutotune.peak = newPeak previousAutotune.peak = newPeak
val localInsulin = LocalInsulin("Ins_$newPeak-$newDia", newPeak, newDia) val localInsulin = LocalInsulin("Ins_$newPeak-$newDia", newPeak, newDia)

View file

@ -1,13 +1,21 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile import info.nightscout.plugins.R
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.androidaps.R import info.nightscout.plugins.general.maintenance.LoggerUtils
import org.json.JSONException import org.json.JSONException
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.* import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.IOException
import java.io.PrintWriter
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
@ -28,7 +36,6 @@ class AutotuneFS @Inject constructor(
val AAPSBOLUSESPREF = "aaps-boluses." val AAPSBOLUSESPREF = "aaps-boluses."
val PREPPEDPREF = "aaps-autotune." val PREPPEDPREF = "aaps-autotune."
val SETTINGS = "settings.json" val SETTINGS = "settings.json"
val PROFIL = "profil"
val PUMPPROFILE = "pumpprofile.json" val PUMPPROFILE = "pumpprofile.json"
val TUNEDPROFILE = "newaapsprofile." val TUNEDPROFILE = "newaapsprofile."
val LOGPREF = "autotune." val LOGPREF = "autotune."

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import android.content.Context import android.content.Context
import android.graphics.Paint import android.graphics.Paint
@ -20,12 +20,10 @@ import android.widget.TextView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.databinding.AutotuneFragmentBinding
import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.extensions.runOnUiThread import info.nightscout.androidaps.extensions.runOnUiThread
import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.extensions.toVisibility
@ -37,16 +35,18 @@ import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
import info.nightscout.androidaps.plugins.general.autotune.events.EventAutotuneUpdateGui
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.plugins.profile.events.EventLocalProfileChanged
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.plugins.R
import info.nightscout.plugins.databinding.AutotuneFragmentBinding
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.events.EventAutotuneUpdateGui
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.plugins.profile.events.EventLocalProfileChanged
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
@ -126,7 +126,7 @@ class AutotuneFragment : DaggerFragment() {
updateGui() updateGui()
} }
binding.autotuneCopylocal.setOnClickListener { binding.autotuneCopyLocal.setOnClickListener {
val localName = rh.gs(R.string.autotune_tunedprofile_name) + " " + dateUtil.dateAndTimeString(autotunePlugin.lastRun) val localName = rh.gs(R.string.autotune_tunedprofile_name) + " " + dateUtil.dateAndTimeString(autotunePlugin.lastRun)
val circadian = sp.getBoolean(R.string.key_autotune_circadian_ic_isf, false) val circadian = sp.getBoolean(R.string.key_autotune_circadian_ic_isf, false)
autotunePlugin.tunedProfile?.let { tunedProfile -> autotunePlugin.tunedProfile?.let { tunedProfile ->
@ -265,14 +265,14 @@ class AutotuneFragment : DaggerFragment() {
} }
} }
binding.tuneLastrun.setOnClickListener { binding.tuneLastRun.setOnClickListener {
if (!autotunePlugin.calculationRunning) { if (!autotunePlugin.calculationRunning) {
autotunePlugin.loadLastRun() autotunePlugin.loadLastRun()
binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble() binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble()
updateGui() updateGui()
} }
} }
binding.tuneLastrun.paintFlags = binding.tuneLastrun.paintFlags or Paint.UNDERLINE_TEXT_FLAG binding.tuneLastRun.paintFlags = binding.tuneLastRun.paintFlags or Paint.UNDERLINE_TEXT_FLAG
} }
@Synchronized @Synchronized
@ -315,7 +315,7 @@ class AutotuneFragment : DaggerFragment() {
} }
binding.autotuneRun.visibility = View.GONE binding.autotuneRun.visibility = View.GONE
binding.autotuneCheckInputProfile.visibility = View.GONE binding.autotuneCheckInputProfile.visibility = View.GONE
binding.autotuneCopylocal.visibility = View.GONE binding.autotuneCopyLocal.visibility = View.GONE
binding.autotuneUpdateProfile.visibility = View.GONE binding.autotuneUpdateProfile.visibility = View.GONE
binding.autotuneRevertProfile.visibility = View.GONE binding.autotuneRevertProfile.visibility = View.GONE
binding.autotuneProfileswitch.visibility = View.GONE binding.autotuneProfileswitch.visibility = View.GONE
@ -326,7 +326,7 @@ class AutotuneFragment : DaggerFragment() {
} }
autotunePlugin.lastRunSuccess -> { autotunePlugin.lastRunSuccess -> {
binding.autotuneCopylocal.visibility = View.VISIBLE binding.autotuneCopyLocal.visibility = View.VISIBLE
binding.autotuneUpdateProfile.visibility = autotunePlugin.updateButtonVisibility binding.autotuneUpdateProfile.visibility = autotunePlugin.updateButtonVisibility
binding.autotuneRevertProfile.visibility = if (autotunePlugin.updateButtonVisibility == View.VISIBLE) View.GONE else View.VISIBLE binding.autotuneRevertProfile.visibility = if (autotunePlugin.updateButtonVisibility == View.VISIBLE) View.GONE else View.VISIBLE
binding.autotuneProfileswitch.visibility = View.VISIBLE binding.autotuneProfileswitch.visibility = View.VISIBLE
@ -339,7 +339,7 @@ class AutotuneFragment : DaggerFragment() {
binding.autotuneCheckInputProfile.visibility = View.VISIBLE binding.autotuneCheckInputProfile.visibility = View.VISIBLE
} }
} }
binding.tuneLastrun.text = dateUtil.dateAndTimeString(autotunePlugin.lastRun) binding.tuneLastRun.text = dateUtil.dateAndTimeString(autotunePlugin.lastRun)
showResults() showResults()
} }

View file

@ -1,29 +1,32 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryBasal
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.extensions.durationInMinutes import info.nightscout.androidaps.extensions.durationInMinutes
import info.nightscout.androidaps.extensions.iobCalc import info.nightscout.androidaps.extensions.iobCalc
import info.nightscout.androidaps.extensions.toJson import info.nightscout.androidaps.extensions.toJson
import info.nightscout.androidaps.extensions.toTemporaryBasal import info.nightscout.androidaps.extensions.toTemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.plugins.R
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.ceil import kotlin.math.ceil
@ -44,7 +47,7 @@ open class AutotuneIob @Inject constructor(
lateinit var glucose: List<GlucoseValue> // newest at index 0 lateinit var glucose: List<GlucoseValue> // newest at index 0
private lateinit var tempBasals: ArrayList<TemporaryBasal> private lateinit var tempBasals: ArrayList<TemporaryBasal>
var startBG: Long = 0 var startBG: Long = 0
var endBG: Long = 0 private var endBG: Long = 0
private fun range(): Long = (60 * 60 * 1000L * dia + T.hours(2).msecs()).toLong() private fun range(): Long = (60 * 60 * 1000L * dia + T.hours(2).msecs()).toLong()
fun initializeData(from: Long, to: Long, tunedProfile: ATProfile) { fun initializeData(from: Long, to: Long, tunedProfile: ATProfile) {
@ -236,11 +239,10 @@ open class AutotuneIob @Inject constructor(
} }
open fun getIOB(time: Long, localInsulin: LocalInsulin): IobTotal { open fun getIOB(time: Long, localInsulin: LocalInsulin): IobTotal {
val bolusIob = getCalculationToTimeTreatments(time, localInsulin).round() return getCalculationToTimeTreatments(time, localInsulin).round()
return bolusIob
} }
fun getCalculationToTimeTreatments(time: Long, localInsulin: LocalInsulin): IobTotal { private fun getCalculationToTimeTreatments(time: Long, localInsulin: LocalInsulin): IobTotal {
val total = IobTotal(time) val total = IobTotal(time)
val detailedLog = sp.getBoolean(R.string.key_autotune_additional_log, false) val detailedLog = sp.getBoolean(R.string.key_autotune_additional_log, false)
for (pos in boluses.indices) { for (pos in boluses.indices) {
@ -257,7 +259,7 @@ open class AutotuneIob @Inject constructor(
} }
fun convertToBoluses(eb: ExtendedBolus): MutableList<Bolus> { private fun convertToBoluses(eb: ExtendedBolus): MutableList<Bolus> {
val result: MutableList<Bolus> = ArrayList() val result: MutableList<Bolus> = ArrayList()
val aboutFiveMinIntervals = ceil(eb.duration / 5.0).toInt() val aboutFiveMinIntervals = ceil(eb.duration / 5.0).toInt()
val spacing = eb.duration / aboutFiveMinIntervals.toDouble() val spacing = eb.duration / aboutFiveMinIntervals.toDouble()
@ -277,7 +279,7 @@ open class AutotuneIob @Inject constructor(
return result return result
} }
fun convertToBoluses(tbr: TemporaryBasal, profile: Profile, tunedProfile: Profile): MutableList<Bolus> { private fun convertToBoluses(tbr: TemporaryBasal, profile: Profile, tunedProfile: Profile): MutableList<Bolus> {
val result: MutableList<Bolus> = ArrayList() val result: MutableList<Bolus> = ArrayList()
val realDuration = tbr.durationInMinutes val realDuration = tbr.durationInMinutes
val basalRate = profile.getBasal(tbr.timestamp) val basalRate = profile.getBasal(tbr.timestamp)

View file

@ -1,32 +1,41 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import android.view.View import android.view.View
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Autotune
import info.nightscout.androidaps.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.Insulin
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.autotune.data.ATProfile
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.androidaps.plugins.general.autotune.events.EventAutotuneUpdateGui
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.plugins.profile.events.EventLocalProfileChanged
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.interfaces.BuildHelper import info.nightscout.plugins.R
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.plugins.general.autotune.events.EventAutotuneUpdateGui
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.plugins.profile.events.EventLocalProfileChanged
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.TimeZone
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -54,7 +63,8 @@ class AutotunePlugin @Inject constructor(
private val buildHelper: BuildHelper, private val buildHelper: BuildHelper,
private val uel: UserEntryLogger, private val uel: UserEntryLogger,
aapsLogger: AAPSLogger aapsLogger: AAPSLogger
) : PluginBase(PluginDescription() ) : PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(AutotuneFragment::class.qualifiedName) .fragmentClass(AutotuneFragment::class.qualifiedName)
.pluginIcon(R.drawable.ic_autotune) .pluginIcon(R.drawable.ic_autotune)
@ -65,6 +75,7 @@ class AutotunePlugin @Inject constructor(
.description(R.string.autotune_description), .description(R.string.autotune_description),
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), Autotune { ), Autotune {
@Volatile override var lastRunSuccess: Boolean = false @Volatile override var lastRunSuccess: Boolean = false
@Volatile var result: String = "" @Volatile var result: String = ""
@Volatile override var calculationRunning: Boolean = false @Volatile override var calculationRunning: Boolean = false
@ -106,7 +117,7 @@ class AutotunePlugin @Inject constructor(
calculationRunning = false calculationRunning = false
return return
} }
selectedProfile = if (profileToTune.isEmpty()) profileFunction.getProfileName() else profileToTune selectedProfile = profileToTune.ifEmpty { profileFunction.getProfileName() }
profileFunction.getProfile()?.let { currentProfile -> profileFunction.getProfile()?.let { currentProfile ->
profile = profileStore.getSpecificProfile(profileToTune)?.let { ProfileSealed.Pure(it) } ?: currentProfile profile = profileStore.getSpecificProfile(profileToTune)?.let { ProfileSealed.Pure(it) } ?: currentProfile
} }
@ -132,7 +143,7 @@ class AutotunePlugin @Inject constructor(
val from = starttime + i * 24 * 60 * 60 * 1000L // get 24 hours BG values from 4 AM to 4 AM next day val from = starttime + i * 24 * 60 * 60 * 1000L // get 24 hours BG values from 4 AM to 4 AM next day
val to = from + 24 * 60 * 60 * 1000L val to = from + 24 * 60 * 60 * 1000L
log("Tune day " + (i + 1) + " of " + daysBack) log("Tune day " + (i + 1) + " of " + daysBack)
tunedProfile?.let { it -> tunedProfile?.let {
autotuneIob.initializeData(from, to, it) //autotuneIob contains BG and Treatments data from history (<=> query for ns-treatments and ns-entries) autotuneIob.initializeData(from, to, it) //autotuneIob contains BG and Treatments data from history (<=> query for ns-treatments and ns-entries)
if (autotuneIob.boluses.size == 0) { if (autotuneIob.boluses.size == 0) {
result = rh.gs(R.string.autotune_error) result = rh.gs(R.string.autotune_error)
@ -209,7 +220,8 @@ class AutotunePlugin @Inject constructor(
UserEntry.Action.PROFILE_SWITCH, UserEntry.Action.PROFILE_SWITCH,
UserEntry.Sources.Automation, UserEntry.Sources.Automation,
rh.gs(R.string.autotune), rh.gs(R.string.autotune),
ValueWithUnit.SimpleString(tunedP.profilename)) ValueWithUnit.SimpleString(tunedP.profilename)
)
} }
rxBus.send(EventLocalProfileChanged()) rxBus.send(EventLocalProfileChanged())
} }
@ -265,8 +277,8 @@ class AutotunePlugin @Inject constructor(
val jsonSettings = JSONObject() val jsonSettings = JSONObject()
val insulinInterface = activePlugin.activeInsulin val insulinInterface = activePlugin.activeInsulin
val utcOffset = T.msecs(TimeZone.getDefault().getOffset(dateUtil.now()).toLong()).hours() val utcOffset = T.msecs(TimeZone.getDefault().getOffset(dateUtil.now()).toLong()).hours()
val startDateString = dateUtil.toISOString(firstloopstart).substring(0,10) val startDateString = dateUtil.toISOString(firstloopstart).substring(0, 10)
val endDateString = dateUtil.toISOString(lastloopend - 24 * 60 * 60 * 1000L).substring(0,10) val endDateString = dateUtil.toISOString(lastloopend - 24 * 60 * 60 * 1000L).substring(0, 10)
val nsUrl = sp.getString(R.string.key_nsclientinternal_url, "") val nsUrl = sp.getString(R.string.key_nsclientinternal_url, "")
val optCategorizeUam = if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) "-c=true" else "" val optCategorizeUam = if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) "-c=true" else ""
val optInsulinCurve = if (sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)) "-i=true" else "" val optInsulinCurve = if (sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)) "-i=true" else ""
@ -291,7 +303,7 @@ class AutotunePlugin @Inject constructor(
val peaktime: Int = insulinInterface.peak val peaktime: Int = insulinInterface.peak
if (insulinInterface.id === Insulin.InsulinType.OREF_ULTRA_RAPID_ACTING) if (insulinInterface.id === Insulin.InsulinType.OREF_ULTRA_RAPID_ACTING)
jsonSettings.put("curve","ultra-rapid") jsonSettings.put("curve", "ultra-rapid")
else if (insulinInterface.id === Insulin.InsulinType.OREF_RAPID_ACTING) else if (insulinInterface.id === Insulin.InsulinType.OREF_RAPID_ACTING)
jsonSettings.put("curve", "rapid-acting") jsonSettings.put("curve", "rapid-acting")
else if (insulinInterface.id === Insulin.InsulinType.OREF_LYUMJEV) { else if (insulinInterface.id === Insulin.InsulinType.OREF_LYUMJEV) {
@ -304,7 +316,9 @@ class AutotunePlugin @Inject constructor(
jsonSettings.put("insulinPeakTime", peaktime) jsonSettings.put("insulinPeakTime", peaktime)
} }
jsonString = jsonSettings.toString(4).replace("\\/", "/") jsonString = jsonSettings.toString(4).replace("\\/", "/")
} catch (e: JSONException) { } } catch (e: JSONException) {
aapsLogger.error(LTag.AUTOTUNE, e.localizedMessage ?: e.toString())
}
return jsonString return jsonString
} }
@ -332,7 +346,7 @@ class AutotunePlugin @Inject constructor(
fun saveLastRun() { fun saveLastRun() {
val json = JSONObject() val json = JSONObject()
json.put("lastNbDays", lastNbDays) json.put("lastNbDays", lastNbDays)
json.put("lastRun",lastRun) json.put("lastRun", lastRun)
json.put("pumpProfile", pumpProfile.profile.toPureNsJson(dateUtil)) json.put("pumpProfile", pumpProfile.profile.toPureNsJson(dateUtil))
json.put("pumpProfileName", pumpProfile.profilename) json.put("pumpProfileName", pumpProfile.profilename)
json.put("pumpPeak", pumpProfile.peak) json.put("pumpPeak", pumpProfile.peak)
@ -378,13 +392,14 @@ class AutotunePlugin @Inject constructor(
atProfile.profilename = tunedProfileName atProfile.profilename = tunedProfileName
atProfile.circadianProfile = ProfileSealed.Pure(circadianTuned) atProfile.circadianProfile = ProfileSealed.Pure(circadianTuned)
for (i in 0..23) { for (i in 0..23) {
atProfile.basalUntuned[i] = JsonHelper.safeGetInt(json,"missingDays_$i") atProfile.basalUntuned[i] = JsonHelper.safeGetInt(json, "missingDays_$i")
} }
} }
result = JsonHelper.safeGetString(json, "result", "") result = JsonHelper.safeGetString(json, "result", "")
updateButtonVisibility = JsonHelper.safeGetInt(json, "updateButtonVisibility") updateButtonVisibility = JsonHelper.safeGetInt(json, "updateButtonVisibility")
lastRunSuccess = true lastRunSuccess = true
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error(LTag.AUTOTUNE, e.localizedMessage ?: e.toString())
} }
} }

View file

@ -1,66 +1,71 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.plugins.general.autotune.data.*
import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.Carbs import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.plugins.R
import info.nightscout.shared.logging.LTag import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.BGDatum
import info.nightscout.plugins.general.autotune.data.CRDatum
import info.nightscout.plugins.general.autotune.data.DiaDeviation
import info.nightscout.plugins.general.autotune.data.PeakDeviation
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
@Singleton @Singleton
class AutotunePrep @Inject constructor( class AutotunePrep @Inject constructor(
private val aapsLogger: AAPSLogger,
private val sp: SP, private val sp: SP,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val autotuneFS: AutotuneFS, private val autotuneFS: AutotuneFS,
private val autotuneIob: AutotuneIob private val autotuneIob: AutotuneIob
) { ) {
fun categorize(tunedprofile: ATProfile): PreppedGlucose? {
val preppedGlucose = categorizeBGDatums(tunedprofile, tunedprofile.localInsulin) fun categorize(tunedProfile: ATProfile): PreppedGlucose? {
val preppedGlucose = categorizeBGDatums(tunedProfile, tunedProfile.localInsulin)
val tuneInsulin = sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false) val tuneInsulin = sp.getBoolean(R.string.key_autotune_tune_insulin_curve, false)
if (tuneInsulin) { if (tuneInsulin) {
var minDeviations = 1000000.0 var minDeviations = 1000000.0
val diaDeviations: MutableList<DiaDeviation> = ArrayList() val diaDeviations: MutableList<DiaDeviation> = ArrayList()
val peakDeviations: MutableList<PeakDeviation> = ArrayList() val peakDeviations: MutableList<PeakDeviation> = ArrayList()
val currentDIA = tunedprofile.localInsulin.dia val currentDIA = tunedProfile.localInsulin.dia
val currentPeak = tunedprofile.localInsulin.peak val currentPeak = tunedProfile.localInsulin.peak
var dia = currentDIA - 2 var dia = currentDIA - 2
val endDIA = currentDIA + 2 val endDIA = currentDIA + 2
while (dia <= endDIA) while (dia <= endDIA) {
{
var sqrtDeviations = 0.0 var sqrtDeviations = 0.0
var deviations = 0.0 var deviations = 0.0
var deviationsSq = 0.0 var deviationsSq = 0.0
val localInsulin = LocalInsulin("Ins_$currentPeak-$dia", currentPeak, dia) val localInsulin = LocalInsulin("Ins_$currentPeak-$dia", currentPeak, dia)
val curve_output = categorizeBGDatums(tunedprofile, localInsulin, false) val curveOutput = categorizeBGDatums(tunedProfile, localInsulin, false)
val basalGlucose = curve_output?.basalGlucoseData val basalGlucose = curveOutput?.basalGlucoseData
basalGlucose?.let { basalGlucose?.let {
for (hour in 0..23) { for (hour in 0..23) {
for (i in 0..(basalGlucose.size-1)) { for (i in basalGlucose.indices) {
val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt() val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt()
if (hour == myHour) { if (hour == myHour) {
sqrtDeviations += Math.pow(Math.abs(basalGlucose[i].deviation), 0.5) sqrtDeviations += abs(basalGlucose[i].deviation).pow(0.5)
deviations += Math.abs(basalGlucose[i].deviation) deviations += abs(basalGlucose[i].deviation)
deviationsSq += Math.pow(basalGlucose[i].deviation, 2.0) deviationsSq += basalGlucose[i].deviation.pow(2.0)
} }
} }
} }
val meanDeviation = Round.roundTo(Math.abs(deviations / basalGlucose.size), 0.001) val meanDeviation = Round.roundTo(abs(deviations / basalGlucose.size), 0.001)
val smrDeviation = Round.roundTo(Math.pow(sqrtDeviations / basalGlucose.size, 2.0), 0.001) val smrDeviation = Round.roundTo((sqrtDeviations / basalGlucose.size).pow(2.0), 0.001)
val rmsDeviation = Round.roundTo(Math.pow(deviationsSq / basalGlucose.size, 0.5), 0.001) val rmsDeviation = Round.roundTo((deviationsSq / basalGlucose.size).pow(0.5), 0.001)
log("insulinEndTime $dia meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)") log("insulinEndTime $dia meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)")
diaDeviations.add( diaDeviations.add(
DiaDeviation( DiaDeviation(
@ -85,31 +90,30 @@ class AutotunePrep @Inject constructor(
minDeviations = 1000000.0 minDeviations = 1000000.0
var peak = currentPeak - 10 var peak = currentPeak - 10
val endPeak = currentPeak + 10 val endPeak = currentPeak + 10
while (peak <= endPeak) while (peak <= endPeak) {
{
var sqrtDeviations = 0.0 var sqrtDeviations = 0.0
var deviations = 0.0 var deviations = 0.0
var deviationsSq = 0.0 var deviationsSq = 0.0
val localInsulin = LocalInsulin("Ins_$peak-$currentDIA", peak, currentDIA) val localInsulin = LocalInsulin("Ins_$peak-$currentDIA", peak, currentDIA)
val curve_output = categorizeBGDatums(tunedprofile, localInsulin, false) val curveOutput = categorizeBGDatums(tunedProfile, localInsulin, false)
val basalGlucose = curve_output?.basalGlucoseData val basalGlucose = curveOutput?.basalGlucoseData
basalGlucose?.let { basalGlucose?.let {
for (hour in 0..23) { for (hour in 0..23) {
for (i in 0..(basalGlucose.size - 1)) { for (i in basalGlucose.indices) {
val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt() val myHour = ((basalGlucose[i].date - MidnightTime.calc(basalGlucose[i].date)) / T.hours(1).msecs()).toInt()
if (hour == myHour) { if (hour == myHour) {
//console.error(basalGlucose[i].deviation); //console.error(basalGlucose[i].deviation);
sqrtDeviations += Math.pow(Math.abs(basalGlucose[i].deviation), 0.5) sqrtDeviations += abs(basalGlucose[i].deviation).pow(0.5)
deviations += Math.abs(basalGlucose[i].deviation) deviations += abs(basalGlucose[i].deviation)
deviationsSq += Math.pow(basalGlucose[i].deviation, 2.0) deviationsSq += basalGlucose[i].deviation.pow(2.0)
} }
} }
} }
val meanDeviation = Round.roundTo(deviations / basalGlucose.size, 0.001) val meanDeviation = Round.roundTo(deviations / basalGlucose.size, 0.001)
val smrDeviation = Round.roundTo(Math.pow(sqrtDeviations / basalGlucose.size, 2.0), 0.001) val smrDeviation = Round.roundTo((sqrtDeviations / basalGlucose.size).pow(2.0), 0.001)
val rmsDeviation = Round.roundTo(Math.pow(deviationsSq / basalGlucose.size, 0.5), 0.001) val rmsDeviation = Round.roundTo((deviationsSq / basalGlucose.size).pow(0.5), 0.001)
log("insulinPeakTime $peak meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)") log("insulinPeakTime $peak meanDeviation: $meanDeviation SMRDeviation: $smrDeviation RMSDeviation: $rmsDeviation (mg/dL)")
peakDeviations.add( peakDeviations.add(
PeakDeviation PeakDeviation
@ -122,7 +126,7 @@ class AutotunePrep @Inject constructor(
) )
} }
deviations = Round.roundTo(deviations, 0.001); deviations = Round.roundTo(deviations, 0.001)
if (deviations < minDeviations) if (deviations < minDeviations)
minDeviations = Round.roundTo(deviations, 0.001) minDeviations = Round.roundTo(deviations, 0.001)
peak += 5 peak += 5
@ -136,7 +140,7 @@ class AutotunePrep @Inject constructor(
} }
// private static Logger log = LoggerFactory.getLogger(AutotunePlugin.class); // private static Logger log = LoggerFactory.getLogger(AutotunePlugin.class);
fun categorizeBGDatums(tunedprofile: ATProfile, localInsulin: LocalInsulin, verbose: Boolean = true): PreppedGlucose? { fun categorizeBGDatums(tunedProfile: ATProfile, localInsulin: LocalInsulin, verbose: Boolean = true): PreppedGlucose? {
//lib/meals is called before to get only meals data (in AAPS it's done in AutotuneIob) //lib/meals is called before to get only meals data (in AAPS it's done in AutotuneIob)
val treatments: MutableList<Carbs> = autotuneIob.meals val treatments: MutableList<Carbs> = autotuneIob.meals
val boluses: MutableList<Bolus> = autotuneIob.boluses val boluses: MutableList<Bolus> = autotuneIob.boluses
@ -148,14 +152,14 @@ class AutotunePrep @Inject constructor(
glucoseData.add(glucose[i]) glucoseData.add(glucose[i])
} }
} }
if (glucose.size == 0 || glucoseData.size == 0 ) { if (glucose.isEmpty() || glucoseData.size == 0) {
//aapsLogger.debug(LTag.AUTOTUNE, "No BG value received") //aapsLogger.debug(LTag.AUTOTUNE, "No BG value received")
if (verbose) if (verbose)
log("No BG value received") log("No BG value received")
return null return null
} }
glucoseData.sortWith(object: Comparator<GlucoseValue>{ override fun compare(o1: GlucoseValue, o2: GlucoseValue): Int = (o2.timestamp - o1.timestamp).toInt() }) glucoseData.sortWith { o1, o2 -> (o2.timestamp - o1.timestamp).toInt() }
// Bloc below replace bloc between #55 and #71 // Bloc below replace bloc between #55 and #71
// boluses and maxCarbs not used here ?, // boluses and maxCarbs not used here ?,
@ -189,10 +193,10 @@ class AutotunePrep @Inject constructor(
var k = 0 // index of first value used by bucket var k = 0 // index of first value used by bucket
//for loop to validate and bucket the data //for loop to validate and bucket the data
for (i in 1 until glucoseData.size) { for (i in 1 until glucoseData.size) {
val BGTime = glucoseData[i].timestamp val bgTime = glucoseData[i].timestamp
val lastBGTime = glucoseData[k].timestamp val lastBGTime = glucoseData[k].timestamp
val elapsedMinutes = (BGTime - lastBGTime) / (60 * 1000) val elapsedMinutes = (bgTime - lastBGTime) / (60 * 1000)
if (Math.abs(elapsedMinutes) >= 2) { if (abs(elapsedMinutes) >= 2) {
//j++; // move to next bucket //j++; // move to next bucket
k = i // store index of first value used by bucket k = i // store index of first value used by bucket
bucketedData.add(BGDatum(glucoseData[i], dateUtil)) bucketedData.add(BGDatum(glucoseData[i], dateUtil))
@ -229,14 +233,14 @@ class AutotunePrep @Inject constructor(
for (i in bucketedData.size - 5 downTo 1) { for (i in bucketedData.size - 5 downTo 1) {
val glucoseDatum = bucketedData[i] val glucoseDatum = bucketedData[i]
//log.debug(glucoseDatum); //log.debug(glucoseDatum);
val BGTime = glucoseDatum.date val bgTime = glucoseDatum.date
// As we're processing each data point, go through the treatment.carbs and see if any of them are older than // As we're processing each data point, go through the treatment.carbs and see if any of them are older than
// the current BG data point. If so, add those carbs to COB. // the current BG data point. If so, add those carbs to COB.
val treatment = if (treatments.size > 0) treatments[treatments.size - 1] else null val treatment = if (treatments.size > 0) treatments[treatments.size - 1] else null
var myCarbs = 0.0 var myCarbs = 0.0
if (treatment != null) { if (treatment != null) {
if (treatment.timestamp < BGTime) { if (treatment.timestamp < bgTime) {
if (treatment.amount > 0.0) { if (treatment.amount > 0.0) {
mealCOB += treatment.amount mealCOB += treatment.amount
mealCarbs += treatment.amount mealCarbs += treatment.amount
@ -267,7 +271,7 @@ class AutotunePrep @Inject constructor(
glucoseDatum.avgDelta = avgDelta glucoseDatum.avgDelta = avgDelta
//sens = ISF //sens = ISF
val sens = tunedprofile.isf val sens = tunedProfile.isf
// for IOB calculations, use the average of the last 4 hours' basals to help convergence; // for IOB calculations, use the average of the last 4 hours' basals to help convergence;
// this helps since the basal this hour could be different from previous, especially if with autotune they start to diverge. // this helps since the basal this hour could be different from previous, especially if with autotune they start to diverge.
@ -280,7 +284,7 @@ class AutotunePrep @Inject constructor(
currentPumpBasal = Round.roundTo(currentPumpBasal / 4, 0.001) //CurrentPumpBasal for iob calculation is average of 4 last pumpProfile Basal rate currentPumpBasal = Round.roundTo(currentPumpBasal / 4, 0.001) //CurrentPumpBasal for iob calculation is average of 4 last pumpProfile Basal rate
*/ */
// this is the current autotuned basal, used for everything else besides IOB calculations // this is the current autotuned basal, used for everything else besides IOB calculations
val currentBasal = tunedprofile.getBasal(BGTime) val currentBasal = tunedProfile.getBasal(bgTime)
// basalBGI is BGI of basal insulin activity. // basalBGI is BGI of basal insulin activity.
val basalBGI = Round.roundTo(currentBasal * sens / 60 * 5, 0.01) // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m val basalBGI = Round.roundTo(currentBasal * sens / 60 * 5, 0.01) // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m
@ -289,14 +293,14 @@ class AutotunePrep @Inject constructor(
//var iob = getIOB(IOBInputs)[0]; //var iob = getIOB(IOBInputs)[0];
// in autotune iob is calculated with 6 hours of history data, tunedProfile and average pumpProfile basal rate... // in autotune iob is calculated with 6 hours of history data, tunedProfile and average pumpProfile basal rate...
//log("currentBasal: " + currentBasal + " BGTime: " + BGTime + " / " + dateUtil!!.timeStringWithSeconds(BGTime) + "******************************************************************************************") //log("currentBasal: " + currentBasal + " BGTime: " + BGTime + " / " + dateUtil!!.timeStringWithSeconds(BGTime) + "******************************************************************************************")
val iob = autotuneIob.getIOB(BGTime, localInsulin) // add localInsulin to be independent to InsulinPlugin val iob = autotuneIob.getIOB(bgTime, localInsulin) // add localInsulin to be independent to InsulinPlugin
// activity times ISF times 5 minutes is BGI // activity times ISF times 5 minutes is BGI
val BGI = Round.roundTo(-iob.activity * sens * 5, 0.01) val bgi = Round.roundTo(-iob.activity * sens * 5, 0.01)
// datum = one glucose data point (being prepped to store in output) // datum = one glucose data point (being prepped to store in output)
glucoseDatum.bgi = BGI glucoseDatum.bgi = bgi
// calculating deviation // calculating deviation
var deviation = avgDelta - BGI var deviation = avgDelta - bgi
// set positive deviations to zero if BG is below 80 // set positive deviations to zero if BG is below 80
if (bg < 80 && deviation > 0) { if (bg < 80 && deviation > 0) {
@ -309,10 +313,10 @@ class AutotunePrep @Inject constructor(
// Then, calculate carb absorption for that 5m interval using the deviation. // Then, calculate carb absorption for that 5m interval using the deviation.
if (mealCOB > 0) { if (mealCOB > 0) {
val ci = Math.max(deviation, sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, 3.0)) val ci = max(deviation, sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, 3.0))
val absorbed = ci * tunedprofile.ic / sens val absorbed = ci * tunedProfile.ic / sens
// Store the COB, and use it as the starting point for the next data point. // Store the COB, and use it as the starting point for the next data point.
mealCOB = Math.max(0.0, mealCOB - absorbed) mealCOB = max(0.0, mealCOB - absorbed)
} }
// Calculate carb ratio (CR) independently of CSF and ISF // Calculate carb ratio (CR) independently of CSF and ISF
@ -323,7 +327,7 @@ class AutotunePrep @Inject constructor(
if (mealCOB > 0 || calculatingCR) { if (mealCOB > 0 || calculatingCR) {
// set initial values when we first see COB // set initial values when we first see COB
crCarbs += myCarbs crCarbs += myCarbs
if (calculatingCR == false) { if (!calculatingCR) {
crInitialIOB = iob.iob crInitialIOB = iob.iob
crInitialBG = glucoseDatum.value crInitialBG = glucoseDatum.value
crInitialCarbTime = glucoseDatum.date crInitialCarbTime = glucoseDatum.date
@ -354,13 +358,13 @@ class AutotunePrep @Inject constructor(
crDatum.crCarbs = crCarbs crDatum.crCarbs = crCarbs
//log.debug(CRDatum); //log.debug(CRDatum);
//String crDataString = "{\"CRInitialIOB\": " + CRInitialIOB + ", \"CRInitialBG\": " + CRInitialBG + ", \"CRInitialCarbTime\": " + CRInitialCarbTime + ", \"CREndIOB\": " + CREndIOB + ", \"CREndBG\": " + CREndBG + ", \"CREndTime\": " + CREndTime + ", \"CRCarbs\": " + CRCarbs + "}"; //String crDataString = "{\"CRInitialIOB\": " + CRInitialIOB + ", \"CRInitialBG\": " + CRInitialBG + ", \"CRInitialCarbTime\": " + CRInitialCarbTime + ", \"CREndIOB\": " + CREndIOB + ", \"CREndBG\": " + CREndBG + ", \"CREndTime\": " + CREndTime + ", \"CRCarbs\": " + CRCarbs + "}";
val CRElapsedMinutes = Math.round((crEndTime - crInitialCarbTime) / (1000 * 60).toFloat()) val crElapsedMinutes = ((crEndTime - crInitialCarbTime) / (1000 * 60).toFloat()).roundToInt()
//log.debug(CREndTime - CRInitialCarbTime, CRElapsedMinutes); //log.debug(CREndTime - CRInitialCarbTime, CRElapsedMinutes);
if (CRElapsedMinutes < 60 || i == 1 && mealCOB > 0) { if (crElapsedMinutes < 60 || i == 1 && mealCOB > 0) {
//aapsLogger.debug(LTag.AUTOTUNE, "Ignoring $CRElapsedMinutes m CR period.") //aapsLogger.debug(LTag.AUTOTUNE, "Ignoring $CRElapsedMinutes m CR period.")
if (verbose) if (verbose)
log("Ignoring $CRElapsedMinutes m CR period.") log("Ignoring $crElapsedMinutes m CR period.")
} else { } else {
crData.add(crDatum) crData.add(crDatum)
} }
@ -376,11 +380,7 @@ class AutotunePrep @Inject constructor(
absorbing = if (iob.iob < currentBasal / 2) { absorbing = if (iob.iob < currentBasal / 2) {
false false
// otherwise, as long as deviations are positive, keep tracking carb deviations // otherwise, as long as deviations are positive, keep tracking carb deviations
} else if (deviation > 0) { } else deviation > 0
true
} else {
false
}
if (!absorbing && mealCOB == 0.0) { if (!absorbing && mealCOB == 0.0) {
mealCarbs = 0.0 mealCarbs = 0.0
} }
@ -405,11 +405,7 @@ class AutotunePrep @Inject constructor(
log("${csfGlucoseData[csfGlucoseData.size - 1].mealAbsorption} carb absorption") log("${csfGlucoseData[csfGlucoseData.size - 1].mealAbsorption} carb absorption")
} }
if (iob.iob > 2 * currentBasal || deviation > 6 || uam) { if (iob.iob > 2 * currentBasal || deviation > 6 || uam) {
uam = if (deviation > 0) { uam = deviation > 0
true
} else {
false
}
if (type != "uam") { if (type != "uam") {
glucoseDatum.uamAbsorption = "start" glucoseDatum.uamAbsorption = "start"
//aapsLogger.debug(LTag.AUTOTUNE, "${glucoseDatum.uamAbsorption} unannnounced meal absorption") //aapsLogger.debug(LTag.AUTOTUNE, "${glucoseDatum.uamAbsorption} unannnounced meal absorption")
@ -431,11 +427,11 @@ class AutotunePrep @Inject constructor(
// When BGI is smaller than about 1/4 of basalBGI, we want to use that data to tune basals // When BGI is smaller than about 1/4 of basalBGI, we want to use that data to tune basals
// When BGI is negative and more than about 1/4 of basalBGI, we can use that data to tune ISF, // When BGI is negative and more than about 1/4 of basalBGI, we can use that data to tune ISF,
// unless avgDelta is positive: then that's some sort of unexplained rise we don't want to use for ISF, so that means basals // unless avgDelta is positive: then that's some sort of unexplained rise we don't want to use for ISF, so that means basals
if (basalBGI > -4 * BGI) { if (basalBGI > -4 * bgi) {
type = "basal" type = "basal"
basalGlucoseData.add(glucoseDatum) basalGlucoseData.add(glucoseDatum)
} else { } else {
if (avgDelta > 0 && avgDelta > -2 * BGI) { if (avgDelta > 0 && avgDelta > -2 * bgi) {
//type="unknown" //type="unknown"
type = "basal" type = "basal"
basalGlucoseData.add(glucoseDatum) basalGlucoseData.add(glucoseDatum)
@ -449,8 +445,12 @@ class AutotunePrep @Inject constructor(
// debug line to print out all the things // debug line to print out all the things
//aapsLogger.debug(LTag.AUTOTUNE, "${(if (absorbing) 1 else 0)} mealCOB: ${Round.roundTo(mealCOB, 0.1)} mealCarbs: ${Math.round(mealCarbs)} basalBGI: ${Round.roundTo(basalBGI, 0.1)} BGI: ${Round.roundTo(BGI, 0.1)} IOB: ${iob.iob} Activity: ${iob.activity} at ${dateUtil.timeStringWithSeconds(BGTime)} dev: $deviation avgDelta: $avgDelta $type") //aapsLogger.debug(LTag.AUTOTUNE, "${(if (absorbing) 1 else 0)} mealCOB: ${Round.roundTo(mealCOB, 0.1)} mealCarbs: ${Math.round(mealCarbs)} basalBGI: ${Round.roundTo(basalBGI, 0.1)} BGI: ${Round.roundTo(BGI, 0.1)} IOB: ${iob.iob} Activity: ${iob.activity} at ${dateUtil.timeStringWithSeconds(BGTime)} dev: $deviation avgDelta: $avgDelta $type")
if (verbose) if (verbose)
log("${(if (absorbing) 1 else 0)} mealCOB: ${Round.roundTo(mealCOB, 0.1)} mealCarbs: ${Math.round(mealCarbs)} basalBGI: ${Round.roundTo(basalBGI, 0.1)} BGI: ${Round log(
.roundTo(BGI, 0.1)} IOB: ${iob.iob} Activity: ${iob.activity} at ${dateUtil.timeStringWithSeconds(BGTime)} dev: $deviation avgDelta: $avgDelta $type") "${(if (absorbing) 1 else 0)} mealCOB: ${Round.roundTo(mealCOB, 0.1)} mealCarbs: ${mealCarbs.roundToInt()} basalBGI: ${Round.roundTo(basalBGI, 0.1)} BGI: ${
Round
.roundTo(bgi, 0.1)
} IOB: ${iob.iob} Activity: ${iob.activity} at ${dateUtil.timeStringWithSeconds(bgTime)} dev: $deviation avgDelta: $avgDelta $type"
)
} }
//**************************************************************************************************************************************** //****************************************************************************************************************************************
@ -460,33 +460,33 @@ class AutotunePrep @Inject constructor(
crDatum.crInsulin = dosed(crDatum.crInitialCarbTime, crDatum.crEndTime, boluses) crDatum.crInsulin = dosed(crDatum.crInitialCarbTime, crDatum.crEndTime, boluses)
} }
// categorize.js Lines 384-436 // categorize.js Lines 384-436
val CSFLength = csfGlucoseData.size val csfLength = csfGlucoseData.size
var ISFLength = isfGlucoseData.size var isfLength = isfGlucoseData.size
val UAMLength = uamGlucoseData.size val uamLength = uamGlucoseData.size
var basalLength = basalGlucoseData.size var basalLength = basalGlucoseData.size
if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) { if (sp.getBoolean(R.string.key_autotune_categorize_uam_as_basal, false)) {
//aapsLogger.debug(LTag.AUTOTUNE, "Categorizing all UAM data as basal.") //aapsLogger.debug(LTag.AUTOTUNE, "Categorizing all UAM data as basal.")
if (verbose) if (verbose)
log("Categorizing all UAM data as basal.") log("Categorizing all UAM data as basal.")
basalGlucoseData.addAll(uamGlucoseData) basalGlucoseData.addAll(uamGlucoseData)
} else if (CSFLength > 12) { } else if (csfLength > 12) {
//aapsLogger.debug(LTag.AUTOTUNE, "Found at least 1h of carb: assuming meals were announced, and categorizing UAM data as basal.") //aapsLogger.debug(LTag.AUTOTUNE, "Found at least 1h of carb: assuming meals were announced, and categorizing UAM data as basal.")
if (verbose) if (verbose)
log("Found at least 1h of carb: assuming meals were announced, and categorizing UAM data as basal.") log("Found at least 1h of carb: assuming meals were announced, and categorizing UAM data as basal.")
basalGlucoseData.addAll(uamGlucoseData) basalGlucoseData.addAll(uamGlucoseData)
} else { } else {
if (2 * basalLength < UAMLength) { if (2 * basalLength < uamLength) {
//log.debug(basalGlucoseData, UAMGlucoseData); //log.debug(basalGlucoseData, UAMGlucoseData);
//aapsLogger.debug(LTag.AUTOTUNE, "Warning: too many deviations categorized as UnAnnounced Meals") //aapsLogger.debug(LTag.AUTOTUNE, "Warning: too many deviations categorized as UnAnnounced Meals")
//aapsLogger.debug(LTag.AUTOTUNE, "Adding $UAMLength UAM deviations to $basalLength basal ones") //aapsLogger.debug(LTag.AUTOTUNE, "Adding $UAMLength UAM deviations to $basalLength basal ones")
if (verbose) { if (verbose) {
log("Warning: too many deviations categorized as UnAnnounced Meals") log("Warning: too many deviations categorized as UnAnnounced Meals")
log("Adding $UAMLength UAM deviations to $basalLength basal ones") log("Adding $uamLength UAM deviations to $basalLength basal ones")
} }
basalGlucoseData.addAll(uamGlucoseData) basalGlucoseData.addAll(uamGlucoseData)
//log.debug(basalGlucoseData); //log.debug(basalGlucoseData);
// if too much data is excluded as UAM, add in the UAM deviations, but then discard the highest 50% // if too much data is excluded as UAM, add in the UAM deviations, but then discard the highest 50%
basalGlucoseData.sortWith(object: Comparator<BGDatum>{ override fun compare(o1: BGDatum, o2: BGDatum): Int = (100 * o1.deviation - 100 * o2.deviation).toInt() }) //deviation rouded to 0.01, so *100 to avoid crash during sort basalGlucoseData.sortWith { o1, o2 -> (100 * o1.deviation - 100 * o2.deviation).toInt() } //deviation rouded to 0.01, so *100 to avoid crash during sort
val newBasalGlucose: MutableList<BGDatum> = ArrayList() val newBasalGlucose: MutableList<BGDatum> = ArrayList()
for (i in 0 until basalGlucoseData.size / 2) { for (i in 0 until basalGlucoseData.size / 2) {
newBasalGlucose.add(basalGlucoseData[i]) newBasalGlucose.add(basalGlucoseData[i])
@ -497,13 +497,13 @@ class AutotunePrep @Inject constructor(
if (verbose) if (verbose)
log("and selecting the lowest 50%, leaving ${basalGlucoseData.size} basal+UAM ones") log("and selecting the lowest 50%, leaving ${basalGlucoseData.size} basal+UAM ones")
} }
if (2 * ISFLength < UAMLength) { if (2 * isfLength < uamLength) {
//aapsLogger.debug(LTag.AUTOTUNE, "Adding $UAMLength UAM deviations to $ISFLength ISF ones") //aapsLogger.debug(LTag.AUTOTUNE, "Adding $UAMLength UAM deviations to $ISFLength ISF ones")
if (verbose) if (verbose)
log("Adding $UAMLength UAM deviations to $ISFLength ISF ones") log("Adding $uamLength UAM deviations to $isfLength ISF ones")
isfGlucoseData.addAll(uamGlucoseData) isfGlucoseData.addAll(uamGlucoseData)
// if too much data is excluded as UAM, add in the UAM deviations to ISF, but then discard the highest 50% // if too much data is excluded as UAM, add in the UAM deviations to ISF, but then discard the highest 50%
isfGlucoseData.sortWith(object: Comparator<BGDatum>{ override fun compare(o1: BGDatum, o2: BGDatum): Int = (100 * o1.deviation - 100 * o2.deviation).toInt() }) //deviation rouded to 0.01, so *100 to avoid crash during sort isfGlucoseData.sortWith { o1, o2 -> (100 * o1.deviation - 100 * o2.deviation).toInt() } //deviation rouded to 0.01, so *100 to avoid crash during sort
val newISFGlucose: MutableList<BGDatum> = ArrayList() val newISFGlucose: MutableList<BGDatum> = ArrayList()
for (i in 0 until isfGlucoseData.size / 2) { for (i in 0 until isfGlucoseData.size / 2) {
newISFGlucose.add(isfGlucoseData[i]) newISFGlucose.add(isfGlucoseData[i])
@ -517,15 +517,15 @@ class AutotunePrep @Inject constructor(
} }
} }
basalLength = basalGlucoseData.size basalLength = basalGlucoseData.size
ISFLength = isfGlucoseData.size isfLength = isfGlucoseData.size
if (4 * basalLength + ISFLength < CSFLength && ISFLength < 10) { if (4 * basalLength + isfLength < csfLength && isfLength < 10) {
//aapsLogger.debug(LTag.AUTOTUNE, "Warning: too many deviations categorized as meals") //aapsLogger.debug(LTag.AUTOTUNE, "Warning: too many deviations categorized as meals")
//aapsLogger.debug(LTag.AUTOTUNE, "Adding $CSFLength CSF deviations to $ISFLength ISF ones") //aapsLogger.debug(LTag.AUTOTUNE, "Adding $CSFLength CSF deviations to $ISFLength ISF ones")
if (verbose) { if (verbose) {
log("Warning: too many deviations categorized as meals") log("Warning: too many deviations categorized as meals")
//log.debug("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones"); //log.debug("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones");
//var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData); //var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData);
log("Adding $CSFLength CSF deviations to $ISFLength ISF ones") log("Adding $csfLength CSF deviations to $isfLength ISF ones")
} }
isfGlucoseData.addAll(csfGlucoseData) isfGlucoseData.addAll(csfGlucoseData)
csfGlucoseData = ArrayList() csfGlucoseData = ArrayList()
@ -543,7 +543,7 @@ class AutotunePrep @Inject constructor(
private fun dosed(start: Long, end: Long, treatments: List<Bolus>): Double { private fun dosed(start: Long, end: Long, treatments: List<Bolus>): Double {
var insulinDosed = 0.0 var insulinDosed = 0.0
//aapsLogger.debug(LTag.AUTOTUNE, "No treatments to process.") //aapsLogger.debug(LTag.AUTOTUNE, "No treatments to process.")
if (treatments.size == 0) { if (treatments.isEmpty()) {
log("No treatments to process.") log("No treatments to process.")
return 0.0 return 0.0
} }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
@ -8,7 +8,14 @@ import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.database.data.Block import info.nightscout.androidaps.database.data.Block
import info.nightscout.androidaps.extensions.blockValueBySeconds import info.nightscout.androidaps.extensions.blockValueBySeconds
import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.Insulin
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
@ -19,7 +26,7 @@ import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.TimeZone
import javax.inject.Inject import javax.inject.Inject
class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector: HasAndroidInjector) { class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector: HasAndroidInjector) {
@ -56,18 +63,19 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
val avgIC: Double val avgIC: Double
get() = if (profile.getIcsValues().size == 1) profile.getIcsValues().get(0).value else Round.roundTo(averageProfileValue(profile.getIcsValues()), 0.01) get() = if (profile.getIcsValues().size == 1) profile.getIcsValues().get(0).value else Round.roundTo(averageProfileValue(profile.getIcsValues()), 0.01)
fun getBasal(timestamp: Long): Double = basal[Profile.secondsFromMidnight(timestamp)/3600] fun getBasal(timestamp: Long): Double = basal[Profile.secondsFromMidnight(timestamp) / 3600]
// for localProfilePlugin Synchronisation // for localProfilePlugin Synchronisation
fun basal() = jsonArray(basal) fun basal() = jsonArray(basal)
fun ic(circadian: Boolean = false): JSONArray { fun ic(circadian: Boolean = false): JSONArray {
if(circadian) if (circadian)
return jsonArray(pumpProfile.icBlocks, avgIC/pumpProfileAvgIC) return jsonArray(pumpProfile.icBlocks, avgIC / pumpProfileAvgIC)
return jsonArray(ic) return jsonArray(ic)
} }
fun isf(circadian: Boolean = false): JSONArray { fun isf(circadian: Boolean = false): JSONArray {
if(circadian) if (circadian)
return jsonArray(pumpProfile.isfBlocks, avgISF/pumpProfileAvgISF) return jsonArray(pumpProfile.isfBlocks, avgISF / pumpProfileAvgISF)
return jsonArray(Profile.fromMgdlToUnits(isf, profile.units)) return jsonArray(Profile.fromMgdlToUnits(isf, profile.units))
} }
@ -115,7 +123,8 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
JSONObject() JSONObject()
.put("start", time) .put("start", time)
.put("minutes", h * 60) .put("minutes", h * 60)
.put("rate", profile.getBasalTimeFromMidnight(secondfrommidnight) .put(
"rate", profile.getBasalTimeFromMidnight(secondfrommidnight)
) )
) )
} }
@ -134,7 +143,8 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
json.put("units", GlucoseUnit.MGDL.asText) json.put("units", GlucoseUnit.MGDL.asText)
json.put("timezone", TimeZone.getDefault().id) json.put("timezone", TimeZone.getDefault().id)
jsonString = json.toString(2).replace("\\/", "/") jsonString = json.toString(2).replace("\\/", "/")
} catch (e: JSONException) {} } catch (e: JSONException) {
}
return jsonString return jsonString
} }
@ -144,8 +154,8 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
try { try {
json.put("dia", dia) json.put("dia", dia)
if (circadian) { if (circadian) {
json.put("sens", jsonArray(pumpProfile.isfBlocks, avgISF/pumpProfileAvgISF)) json.put("sens", jsonArray(pumpProfile.isfBlocks, avgISF / pumpProfileAvgISF))
json.put("carbratio", jsonArray(pumpProfile.icBlocks, avgIC/pumpProfileAvgIC)) json.put("carbratio", jsonArray(pumpProfile.icBlocks, avgIC / pumpProfileAvgIC))
} else { } else {
json.put("sens", jsonArray(Profile.fromMgdlToUnits(isf, profile.units))) json.put("sens", jsonArray(Profile.fromMgdlToUnits(isf, profile.units)))
json.put("carbratio", jsonArray(ic)) json.put("carbratio", jsonArray(ic))
@ -156,8 +166,7 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
return pureProfileFromJson(json, dateUtil, profile.units.asText) return pureProfileFromJson(json, dateUtil, profile.units.asText)
} }
fun profileStore(circadian: Boolean = false): ProfileStore? fun profileStore(circadian: Boolean = false): ProfileStore? {
{
var profileStore: ProfileStore? = null var profileStore: ProfileStore? = null
val json = JSONObject() val json = JSONObject()
val store = JSONObject() val store = JSONObject()
@ -170,7 +179,8 @@ class ATProfile(profile: Profile, var localInsulin: LocalInsulin, val injector:
json.put("store", store) json.put("store", store)
json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now())) json.put("startDate", dateUtil.toISOAsUTC(dateUtil.now()))
profileStore = ProfileStore(injector, json, dateUtil) profileStore = ProfileStore(injector, json, dateUtil)
} catch (e: JSONException) { } } catch (e: JSONException) {
}
return profileStore return profileStore
} }

View file

@ -1,17 +1,18 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import info.nightscout.androidaps.database.entities.GlucoseValue.TrendArrow
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.GlucoseValue.TrendArrow
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.TimeZone
/** /**
* Created by Rumen Georgiev on 2/24/2018. * Created by Rumen Georgiev on 2/24/2018.
*/ */
class BGDatum { class BGDatum {
//Added by Rumen for autotune //Added by Rumen for autotune
var id: Long = 0 var id: Long = 0
var date = 0L var date = 0L
@ -27,7 +28,10 @@ class BGDatum {
private set private set
var dateUtil: DateUtil var dateUtil: DateUtil
constructor(dateUtil: DateUtil) { this.dateUtil = dateUtil} constructor(dateUtil: DateUtil) {
this.dateUtil = dateUtil
}
constructor(json: JSONObject, dateUtil: DateUtil) { constructor(json: JSONObject, dateUtil: DateUtil) {
this.dateUtil = dateUtil this.dateUtil = dateUtil
try { try {

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException import org.json.JSONException
@ -20,7 +20,10 @@ class CRDatum {
var crInsulinTotal = 0.0 var crInsulinTotal = 0.0
var dateUtil: DateUtil var dateUtil: DateUtil
constructor(dateUtil: DateUtil) { this.dateUtil = dateUtil} constructor(dateUtil: DateUtil) {
this.dateUtil = dateUtil
}
constructor(json: JSONObject, dateUtil: DateUtil) { constructor(json: JSONObject, dateUtil: DateUtil) {
this.dateUtil = dateUtil this.dateUtil = dateUtil
try { try {

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject

View file

@ -1,10 +1,9 @@
package info.nightscout.androidaps.plugins.general.autotune.data package info.nightscout.plugins.general.autotune.data
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.*
class PreppedGlucose { class PreppedGlucose {

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.general.autotune.events package info.nightscout.plugins.general.autotune.events
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.general.maintenance package info.nightscout.plugins.general.maintenance
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -21,7 +22,7 @@ class LoggerUtils @Inject constructor(
* *
* @return * @return
*/ */
/* /*
This is failing after slf4j update to 2.0.0 This is failing after slf4j update to 2.0.0
It would be better to find a way to read the value from xml It would be better to find a way to read the value from xml
So far replaced by static value So far replaced by static value
@ -30,6 +31,6 @@ class LoggerUtils @Inject constructor(
val lc = LoggerFactory.getILoggerFactory() as LoggerContext val lc = LoggerFactory.getILoggerFactory() as LoggerContext
return lc.getProperty("EXT_FILES_DIR") return lc.getProperty("EXT_FILES_DIR")
} }
*/ */
val logDirectory get() = prefFileListProvider.logsPath val logDirectory get() = prefFileListProvider.logsPath
} }

View file

@ -0,0 +1,20 @@
package info.nightscout.plugins.utils
import kotlin.math.floor
object Percentile {
// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
fun percentile(arr: Array<Double>, p: Double): Double {
if (arr.isEmpty()) return 0.0
if (p <= 0) return arr[0]
if (p >= 1) return arr[arr.size - 1]
val index = arr.size * p
val lower = floor(index)
val upper = lower + 1
val weight = index % 1
return if (upper >= arr.size) arr[lower.toInt()] else arr[lower.toInt()] * (1 - weight) + arr[upper.toInt()] * weight
}
}

View file

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".plugins.general.autotune.AutotuneFragment"> tools:context="info.nightscout.plugins.general.autotune.AutotuneFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -133,7 +133,7 @@
android:textSize="14sp" /> android:textSize="14sp" />
<TextView <TextView
android:id="@+id/tune_lastrun" android:id="@+id/tune_last_run"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
@ -246,7 +246,7 @@
app:layout_row="0" /> app:layout_row="0" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/autotune_copylocal" android:id="@+id/autotune_copy_local"
style="@style/GrayButton" style="@style/GrayButton"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -1,18 +1,19 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.database.data.Block import info.nightscout.androidaps.database.data.Block
import info.nightscout.androidaps.database.data.TargetBlock import info.nightscout.androidaps.database.data.TargetBlock
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.plugins.general.autotune.data.*
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.plugins.R
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
@ -22,14 +23,13 @@ import org.junit.Test
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import java.io.File import java.io.File
import java.util.* import java.util.TimeZone
class AutotuneCoreTest : TestBaseWithProfile() { class AutotuneCoreTest : TestBaseWithProfile() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var autotuneFS: AutotuneFS @Mock lateinit var autotuneFS: AutotuneFS
@Mock lateinit var injector: HasAndroidInjector @Mock lateinit var injector: HasAndroidInjector
@Mock lateinit var activePlugin: ActivePlugin
private lateinit var autotuneCore: AutotuneCore private lateinit var autotuneCore: AutotuneCore
private var min5mCarbImpact = 0.0 private var min5mCarbImpact = 0.0
private var autotuneMin = 0.0 private var autotuneMin = 0.0

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.LocalInsulin import info.nightscout.androidaps.data.LocalInsulin
@ -14,11 +13,14 @@ import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.Carbs import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.extensions.shiftBlock import info.nightscout.androidaps.extensions.shiftBlock
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.plugins.general.autotune.data.* import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.plugins.R
import info.nightscout.plugins.general.autotune.data.ATProfile
import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
@ -29,14 +31,13 @@ import org.junit.Test
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import java.io.File import java.io.File
import java.util.* import java.util.TimeZone
class AutotunePrepTest : TestBaseWithProfile() { class AutotunePrepTest : TestBaseWithProfile() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var autotuneFS: AutotuneFS @Mock lateinit var autotuneFS: AutotuneFS
@Mock lateinit var injector: HasAndroidInjector @Mock lateinit var injector: HasAndroidInjector
@Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
private lateinit var autotunePrep: AutotunePrep private lateinit var autotunePrep: AutotunePrep
private lateinit var autotuneIob: TestAutotuneIob private lateinit var autotuneIob: TestAutotuneIob
@ -55,8 +56,8 @@ class AutotunePrepTest : TestBaseWithProfile() {
fun autotunePrepTest1() { // Test if categorisation with standard treatments with carbs is Ok fun autotunePrepTest1() { // Test if categorisation with standard treatments with carbs is Ok
val inputIobJson = File("src/test/res/autotune/test1/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS val inputIobJson = File("src/test/res/autotune/test1/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS
val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson)) val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson))
autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, activePlugin, autotuneFS, iobOapsCalculation) autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, autotuneFS, iobOapsCalculation)
autotunePrep = AutotunePrep(aapsLogger, sp, dateUtil, autotuneFS, autotuneIob) autotunePrep = AutotunePrep(sp, dateUtil, autotuneFS, autotuneIob)
val inputProfileJson = File("src/test/res/autotune/test1/profile.pump.json").readText() val inputProfileJson = File("src/test/res/autotune/test1/profile.pump.json").readText()
val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!! val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!!
val prepJson = File("src/test/res/autotune/test1/autotune.2022-05-21.json").readText() val prepJson = File("src/test/res/autotune/test1/autotune.2022-05-21.json").readText()
@ -94,8 +95,8 @@ class AutotunePrepTest : TestBaseWithProfile() {
fun autotunePrepTest2() { // Test if categorisation without carbs (full UAM) and categorize UAM as basal false is Ok fun autotunePrepTest2() { // Test if categorisation without carbs (full UAM) and categorize UAM as basal false is Ok
val inputIobJson = File("src/test/res/autotune/test2/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS val inputIobJson = File("src/test/res/autotune/test2/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS
val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson)) val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson))
autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, activePlugin, autotuneFS, iobOapsCalculation) autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, autotuneFS, iobOapsCalculation)
autotunePrep = AutotunePrep(aapsLogger, sp, dateUtil, autotuneFS, autotuneIob) autotunePrep = AutotunePrep(sp, dateUtil, autotuneFS, autotuneIob)
val inputProfileJson = File("src/test/res/autotune/test2/profile.pump.json").readText() val inputProfileJson = File("src/test/res/autotune/test2/profile.pump.json").readText()
val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!! val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!!
val prepJson = File("src/test/res/autotune/test2/autotune.2022-05-21.json").readText() val prepJson = File("src/test/res/autotune/test2/autotune.2022-05-21.json").readText()
@ -133,8 +134,8 @@ class AutotunePrepTest : TestBaseWithProfile() {
fun autotunePrepTest3() { // Test if categorisation without carbs (full UAM) and categorize UAM as basal true is Ok fun autotunePrepTest3() { // Test if categorisation without carbs (full UAM) and categorize UAM as basal true is Ok
val inputIobJson = File("src/test/res/autotune/test3/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS val inputIobJson = File("src/test/res/autotune/test3/oaps-iobCalc.2022-05-21.json").readText() //json files build with iob/activity calculated by OAPS
val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson)) val iobOapsCalculation = buildIobOaps(JSONArray(inputIobJson))
autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, activePlugin, autotuneFS, iobOapsCalculation) autotuneIob = TestAutotuneIob(aapsLogger, repository, profileFunction, sp, dateUtil, autotuneFS, iobOapsCalculation)
autotunePrep = AutotunePrep(aapsLogger, sp, dateUtil, autotuneFS, autotuneIob) autotunePrep = AutotunePrep(sp, dateUtil, autotuneFS, autotuneIob)
val inputProfileJson = File("src/test/res/autotune/test3/profile.pump.json").readText() val inputProfileJson = File("src/test/res/autotune/test3/profile.pump.json").readText()
val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!! val inputProfile = atProfileFromOapsJson(JSONObject(inputProfileJson), dateUtil)!!
val prepJson = File("src/test/res/autotune/test3/autotune.2022-05-21.json").readText() val prepJson = File("src/test/res/autotune/test3/autotune.2022-05-21.json").readText()
@ -305,10 +306,9 @@ class AutotunePrepTest : TestBaseWithProfile() {
class TestAutotuneIob( class TestAutotuneIob(
val aapsLogger: AAPSLogger, val aapsLogger: AAPSLogger,
repository: AppRepository, repository: AppRepository,
val profileFunction: ProfileFunction, profileFunction: ProfileFunction,
val sp: SP, sp: SP,
val dateUtil: DateUtil, dateUtil: DateUtil,
val activePlugin: ActivePlugin,
autotuneFS: AutotuneFS, autotuneFS: AutotuneFS,
private val iobOapsCalculation: ArrayList<IobTotal> private val iobOapsCalculation: ArrayList<IobTotal>
) : AutotuneIob( ) : AutotuneIob(

View file

@ -1,9 +1,9 @@
package info.nightscout.androidaps.plugins.general.autotune package info.nightscout.plugins.general.autotune
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.plugins.general.autotune.data.BGDatum import info.nightscout.plugins.general.autotune.data.BGDatum
import info.nightscout.androidaps.plugins.general.autotune.data.CRDatum import info.nightscout.plugins.general.autotune.data.CRDatum
import info.nightscout.androidaps.plugins.general.autotune.data.PreppedGlucose import info.nightscout.plugins.general.autotune.data.PreppedGlucose
import org.json.JSONObject import org.json.JSONObject
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before

View file

@ -28,7 +28,6 @@
<string name="invalid_weight">Invalid weight entry</string> <string name="invalid_weight">Invalid weight entry</string>
<string name="id">ID:</string> <string name="id">ID:</string>
<string name="submit">Submit</string> <string name="submit">Submit</string>
<string name="profile">Profile</string>
<string name="age">Age</string> <string name="age">Age</string>
<string name="weight_label">Weight</string> <string name="weight_label">Weight</string>
<string name="most_common_profile">Most common profile:</string> <string name="most_common_profile">Most common profile:</string>