From c637b7072c0e5f305fec63effa607f854dff403f Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Mon, 12 Apr 2021 19:49:12 +0200 Subject: [PATCH] IobCobCalculator refactor --- .../androidaps/dialogs/CarbsDialog.kt | 16 +- .../openAPSAMA/DetermineBasalAdapterAMAJS.kt | 7 +- .../aps/openAPSAMA/OpenAPSAMAPlugin.kt | 4 +- .../aps/openAPSSMB/OpenAPSSMBPlugin.kt | 4 +- .../objectives/objectives/Objective0.kt | 6 +- .../general/overview/graphData/GraphData.kt | 6 +- .../general/wear/ActionStringHandler.kt | 23 ++- .../IobCobCalculatorPlugin.kt | 81 +++++----- .../iob/iobCobCalculator/IobCobOref1Thread.kt | 6 +- .../iob/iobCobCalculator/IobCobThread.kt | 6 +- .../sensitivity/SensitivityOref1Plugin.kt | 10 +- .../androidaps/receivers/KeepAliveReceiver.kt | 10 +- .../androidaps/utils/LocalAlertUtils.kt | 6 +- .../interfaces/ConstraintsCheckerTest.kt | 3 +- .../SmsCommunicatorPluginTest.kt | 11 +- .../IobCobCalculatorPluginTest.kt | 11 +- .../utils/wizard/BolusWizardTest.kt | 4 +- .../general/automation/triggers/Trigger.kt | 2 +- .../triggers/TriggerAutosensValue.kt | 2 +- .../general/automation/triggers/TriggerCOB.kt | 2 +- .../general/automation/triggers/TriggerIob.kt | 2 +- .../triggers/TriggerAutosensValueTest.kt | 6 +- .../automation/triggers/TriggerBgTest.kt | 5 +- .../automation/triggers/TriggerCOBTest.kt | 2 +- .../automation/triggers/TriggerDeltaTest.kt | 7 +- .../automation/triggers/TriggerIobTest.kt | 2 +- .../automation/triggers/TriggerTestBase.kt | 8 +- .../androidaps/interfaces/IobCobCalculator.kt | 23 +-- .../iobCobCalculator/GlucoseStatusProvider.kt | 152 +++++++++--------- .../iob/iobCalculator/GlucoseStatusTest.kt | 16 +- 30 files changed, 222 insertions(+), 221 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt index ce7fc47e3a..b2b60d9377 100644 --- a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt @@ -14,24 +14,24 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.database.AppRepository -import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Sources +import info.nightscout.androidaps.database.entities.ValueWithUnit import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.databinding.DialogCarbsBinding +import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.alertDialogs.OKDialog -import info.nightscout.androidaps.extensions.formatColor import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.plusAssign @@ -49,7 +49,7 @@ class CarbsDialog : DialogFragmentWithDate() { @Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var profileFunction: ProfileFunction - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var uel: UserEntryLogger @Inject lateinit var carbTimer: CarbTimer @Inject lateinit var commandQueue: CommandQueue @@ -144,7 +144,7 @@ class CarbsDialog : DialogFragmentWithDate() { validateInputs() } - iobCobCalculatorPlugin.actualBg()?.let { bgReading -> + iobCobCalculator.actualBg()?.let { bgReading -> if (bgReading.value < 72) binding.hypoTt.isChecked = true } @@ -226,7 +226,7 @@ class CarbsDialog : DialogFragmentWithDate() { activitySelected -> { uel.log(Action.TT, Sources.CarbDialog, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY), - ValueWithUnit.fromGlucoseUnit(activityTT, units) , + ValueWithUnit.fromGlucoseUnit(activityTT, units), ValueWithUnit.Minute(activityTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), @@ -245,7 +245,7 @@ class CarbsDialog : DialogFragmentWithDate() { eatingSoonSelected -> { uel.log(Action.TT, Sources.CarbDialog, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON), - ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units) , + ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units), ValueWithUnit.Minute(eatingSoonTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), @@ -264,7 +264,7 @@ class CarbsDialog : DialogFragmentWithDate() { hypoSelected -> { uel.log(Action.TT, Sources.CarbDialog, ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA), - ValueWithUnit.fromGlucoseUnit(hypoTT, units) , + ValueWithUnit.fromGlucoseUnit(hypoTT, units), ValueWithUnit.Minute(hypoTTDuration)) disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( timestamp = System.currentTimeMillis(), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt index 076618f6b1..c4e858f76c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.kt @@ -6,6 +6,9 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.extensions.convertedToAbsolute +import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes +import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger @@ -16,10 +19,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin -import info.nightscout.androidaps.extensions.convertedToAbsolute -import info.nightscout.androidaps.extensions.getPassedDurationToTimeInMinutes -import info.nightscout.androidaps.extensions.plannedRemainingMinutes import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONArray import org.json.JSONException diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt index 891a14239a..ccb16a6665 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.kt @@ -107,7 +107,7 @@ open class OpenAPSAMAPlugin @Inject constructor( val iobArray = iobCobCalculator.calculateIobArrayInDia(profile) profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart) startPart = System.currentTimeMillis() - val mealData = iobCobCalculator.mealData + val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish() profiler.log(LTag.APS, "getMealData()", startPart) val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint -> inputConstraints.copyReasons(maxIOBAllowedConstraint) @@ -130,7 +130,7 @@ open class OpenAPSAMAPlugin @Inject constructor( if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return startPart = System.currentTimeMillis() if (constraintChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") if (autosensData == null) { rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) return diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt index 6517feb45c..7aafe2883f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.kt @@ -136,7 +136,7 @@ open class OpenAPSSMBPlugin @Inject constructor( if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return startPart = System.currentTimeMillis() if (constraintChecker.isAutosensModeEnabled().value()) { - val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin") if (autosensData == null) { rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) return @@ -169,7 +169,7 @@ open class OpenAPSSMBPlugin @Inject constructor( activePlugin.activePump.baseBasalRate, iobArray, glucoseStatus, - iobCobCalculator.mealData, + iobCobCalculator.getMealDataWithWaitingForCalculationFinish(), lastAutosensResult.ratio, isTempTarget, smbAllowed.value(), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt index feb7fe73d7..3250bbb4a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.kt @@ -3,11 +3,11 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import javax.inject.Inject @@ -19,7 +19,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R @Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator init { tasks.add(object : Task(this, R.string.objectives_bgavailableinns) { @@ -48,7 +48,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R }) tasks.add(object : Task(this, R.string.hasbgdata) { override fun isCompleted(): Boolean { - return iobCobCalculatorPlugin.lastBg() != null + return iobCobCalculator.lastBg() != null } }) tasks.add(object : Task(this, R.string.loopenabled) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index b60fa269a3..c1436bdbe1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -62,7 +62,7 @@ class GraphData( } fun addBucketedData(fromTime: Long, toTime: Long) { - val bucketedData = iobCobCalculator.bucketedData ?: return + val bucketedData = iobCobCalculator.getBucketedDataTableCopy() ?: return if (bucketedData.isEmpty()) { aapsLogger.debug("No bucketed data.") return @@ -70,7 +70,7 @@ class GraphData( val bucketedListArray: MutableList = ArrayList() for (inMemoryGlucoseValue in bucketedData) { if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue - bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, qgiprofileFunction, resourceHelper)) + bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper)) } addSeries(PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] })) } @@ -426,7 +426,7 @@ class GraphData( it.thickness = 3 } if (showPrediction) { - val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("GraphData") + val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData") val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing val iobPrediction: MutableList = ArrayList() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt index cfc399335d..38cd6992fa 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt @@ -23,6 +23,7 @@ import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.db.TDD +import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -33,11 +34,9 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.* -import info.nightscout.androidaps.extensions.valueToUnits import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -71,7 +70,7 @@ class ActionStringHandler @Inject constructor( private val fabricPrivacy: FabricPrivacy, private val commandQueue: CommandQueueProvider, private val activePlugin: ActivePluginProvider, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val localInsightPlugin: LocalInsightPlugin, private val danaRPlugin: DanaRPlugin, private val danaRKoreanPlugin: DanaRKoreanPlugin, @@ -104,7 +103,7 @@ class ActionStringHandler @Inject constructor( .subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException) } - fun tearDown(){ + fun tearDown() { disposable.clear() } @@ -208,12 +207,12 @@ class ActionStringHandler @Inject constructor( sendError("No profile found!") return } - val bgReading = iobCobCalculatorPlugin.actualBg() + val bgReading = iobCobCalculator.actualBg() if (bgReading == null) { sendError("No recent BG to base calculation on!") return } - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear") + val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear") if (cobInfo.displayCob == null) { sendError("Unknown COB! BG reading missing or recent app restart?") return @@ -624,10 +623,10 @@ class ActionStringHandler @Inject constructor( } private fun doECarbs(carbs: Int, time: Long, duration: Int) { - uel.log(if (duration==0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear, + uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear, ValueWithUnit.Timestamp(time), ValueWithUnit.Gram(carbs), - ValueWithUnit.Hour(duration).takeIf { duration !=0 }) + ValueWithUnit.Hour(duration).takeIf { duration != 0 }) doBolus(0.0, carbs, time, duration) } @@ -640,10 +639,10 @@ class ActionStringHandler @Inject constructor( detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs() if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { val action = when { - amount.equals(0.0) -> Action.CARBS - carbs.equals(0) -> Action.BOLUS - carbsDuration>0 -> Action.EXTENDED_CARBS - else -> Action.TREATMENT + amount.equals(0.0) -> Action.CARBS + carbs.equals(0) -> Action.BOLUS + carbsDuration > 0 -> Action.EXTENDED_CARBS + else -> Action.TREATMENT } uel.log(action, Sources.Wear, ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 }, diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt index f9860a1f6d..e0ec623171 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.kt @@ -78,9 +78,9 @@ open class IobCobCalculatorPlugin @Inject constructor( private var absIobTable = LongSparseArray() // oldest at index 0, absolute insulin in the body private var autosensDataTable = LongSparseArray() // oldest at index 0 private var basalDataTable = LongSparseArray() // oldest at index 0 - override var bgReadings: List = listOf() // newest at index 0 + internal var bgReadings: List = listOf() // newest at index 0 - @Volatile override var bucketedData: MutableList? = null + internal var bucketedData: MutableList? = null // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime @@ -135,9 +135,9 @@ open class IobCobCalculatorPlugin @Inject constructor( super.onStop() } - override fun getAutosensDataTable(): LongSparseArray { - return autosensDataTable - } + override fun getBgReadingsDataTableCopy(): List = bgReadings.toList() + override fun getBucketedDataTableCopy(): MutableList? = bucketedData?.toMutableList() + override fun getAutosensDataTable(): LongSparseArray = autosensDataTable private fun adjustToReferenceTime(someTime: Long): Long { if (referenceTime == -1L) { @@ -503,7 +503,7 @@ open class IobCobCalculatorPlugin @Inject constructor( } } - override fun getLastAutosensDataSynchronized(reason: String): AutosensData? { + override fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? { if (thread?.isAlive == true) { aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason") try { @@ -515,8 +515,10 @@ open class IobCobCalculatorPlugin @Inject constructor( synchronized(dataLock) { return getLastAutosensData(reason) } } - override fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo { - val autosensData = if (_synchronized) getLastAutosensDataSynchronized(reason) else getLastAutosensData(reason) + override fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo { + val autosensData = + if (waitForCalculationFinish) getLastAutosensDataWithWaitForCalculationFinish(reason) + else getLastAutosensData(reason) var displayCob: Double? = null var futureCarbs = 0.0 val now = dateUtil.now() @@ -576,39 +578,38 @@ open class IobCobCalculatorPlugin @Inject constructor( } } - override fun lastDataTime(): String { - return if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) else "autosensDataTable empty" - } + override fun lastDataTime(): String = + if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) + else "autosensDataTable empty" - override val mealData: MealData - get() { - val result = MealData() - val now = System.currentTimeMillis() - val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { - sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } else { - sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) - } - val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong() - repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true) - .blockingGet() - .forEach { - if (it.amount > 0) { - result.carbs += it.amount - if (it.timestamp > result.lastCarbTime) result.lastCarbTime = it.timestamp - } - } - val autosensData = getLastAutosensDataSynchronized("getMealData()") - if (autosensData != null) { - result.mealCOB = autosensData.cob - result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation - result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation - result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact - } - val lastBolus = repository.getLastBolusRecordWrapped().blockingGet() - result.lastBolusTime = if (lastBolus is ValueWrapper.Existing) lastBolus.value.timestamp else 0L - return result + override fun getMealDataWithWaitingForCalculationFinish(): MealData { + val result = MealData() + val now = System.currentTimeMillis() + val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { + sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) + } else { + sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME) } + val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong() + repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true) + .blockingGet() + .forEach { + if (it.amount > 0) { + result.carbs += it.amount + if (it.timestamp > result.lastCarbTime) result.lastCarbTime = it.timestamp + } + } + val autosensData = getLastAutosensDataWithWaitForCalculationFinish("getMealData()") + if (autosensData != null) { + result.mealCOB = autosensData.cob + result.slopeFromMinDeviation = autosensData.slopeFromMinDeviation + result.slopeFromMaxDeviation = autosensData.slopeFromMaxDeviation + result.usedMinCarbsImpact = autosensData.usedMinCarbsImpact + } + val lastBolus = repository.getLastBolusRecordWrapped().blockingGet() + result.lastBolusTime = if (lastBolus is ValueWrapper.Existing) lastBolus.value.timestamp else 0L + return result + } override fun calculateIobArrayInDia(profile: Profile): Array { // predict IOB out to DIA plus 30m @@ -656,7 +657,7 @@ open class IobCobCalculatorPlugin @Inject constructor( if (thread?.state != Thread.State.TERMINATED) { stopCalculationTrigger = true aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") - while (thread?.state != Thread.State.TERMINATED) { + while (thread != null && thread?.state != Thread.State.TERMINATED) { SystemClock.sleep(100) } aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt index c07bc0cebd..d4edd942b0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.kt @@ -81,7 +81,7 @@ class IobCobOref1Thread internal constructor( iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.createBucketedData() } - val bucketedData = iobCobCalculatorPlugin.bucketedData + val bucketedData = iobCobCalculatorPlugin.getBucketedDataTableCopy() val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() if (bucketedData == null || bucketedData.size < 3) { aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") @@ -156,7 +156,7 @@ class IobCobOref1Thread internal constructor( if (ad == null) { aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) - aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) + //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) @@ -179,7 +179,7 @@ class IobCobOref1Thread internal constructor( fabricPrivacy.logException(e) aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(bucketedData.toString()) - aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) + //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt index 5f3343e339..69f2eb6c39 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.kt @@ -79,7 +79,7 @@ class IobCobThread @Inject internal constructor( iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.createBucketedData() } - val bucketedData = iobCobCalculatorPlugin.bucketedData + val bucketedData = iobCobCalculatorPlugin.getBucketedDataTableCopy() val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() if (bucketedData == null || bucketedData.size < 3) { aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") @@ -152,7 +152,7 @@ class IobCobThread @Inject internal constructor( if (ad == null) { aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) - aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.bgReadings.toString()) + //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) @@ -175,7 +175,7 @@ class IobCobThread @Inject internal constructor( fabricPrivacy.logException(e) aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(bucketedData.toString()) - aapsLogger.debug(iobCobCalculatorPlugin.bgReadings.toString()) + //aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) sp.putBoolean("log_AUTOSENS", true) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt index 42cf28d3cd..e4d90b0496 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/sensitivity/SensitivityOref1Plugin.kt @@ -31,10 +31,10 @@ import kotlin.math.roundToInt @Singleton open class SensitivityOref1Plugin @Inject constructor( - injector: HasAndroidInjector?, - aapsLogger: AAPSLogger?, - resourceHelper: ResourceHelper?, - sp: SP?, + injector: HasAndroidInjector, + aapsLogger: AAPSLogger, + resourceHelper: ResourceHelper, + sp: SP, private val profileFunction: ProfileFunction, private val dateUtil: DateUtil, private val databaseHelper: DatabaseHelperInterface, @@ -48,7 +48,7 @@ open class SensitivityOref1Plugin @Inject constructor( .preferencesId(R.xml.pref_absorption_oref1) .description(R.string.description_sensitivity_oref1) .setDefault(), - injector!!, aapsLogger!!, resourceHelper!!, sp!! + injector, aapsLogger, resourceHelper, sp ) { override fun detectSensitivity(plugin: IobCobCalculator, fromTime: Long, toTime: Long): AutosensResult { diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt index 8cd383cb6b..6b73006547 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.kt @@ -17,21 +17,21 @@ import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.Config import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.EventProfileNeedsUpdate +import info.nightscout.androidaps.extensions.buildDeviceStatus import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.LocalAlertUtils import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.extensions.buildDeviceStatus import javax.inject.Inject import kotlin.math.abs @@ -61,7 +61,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() { @Inject lateinit var localAlertUtils: LocalAlertUtils @Inject lateinit var repository: AppRepository @Inject lateinit var config: Config - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var dateUtil: DateUtil @Inject lateinit var activePlugin: ActivePluginProvider @@ -102,12 +102,12 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() { var shouldUploadStatus = false if (config.NSCLIENT) return if (config.PUMPCONTROL) shouldUploadStatus = true - else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null) + else if (!loopPlugin.isEnabled() || iobCobCalculator.actualBg() == null) shouldUploadStatus = true else if (dateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true if (dateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) { lastIobUpload = dateUtil.now() - buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculatorPlugin, profileFunction, + buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculator, profileFunction, activePlugin.activePump, receiverStatusStore, runningConfiguration, BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { repository.insert(it) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt b/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt index a764509a8b..1c6101e4ce 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/LocalAlertUtils.kt @@ -6,6 +6,7 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag @@ -14,7 +15,6 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.disposables.CompositeDisposable @@ -34,7 +34,7 @@ class LocalAlertUtils @Inject constructor( private val resourceHelper: ResourceHelper, private val activePlugin: ActivePluginProvider, private val profileFunction: ProfileFunction, - private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, + private val iobCobCalculator: IobCobCalculator, private val smsCommunicatorPlugin: SmsCommunicatorPlugin, private val config: Config, private val repository: AppRepository, @@ -110,7 +110,7 @@ class LocalAlertUtils @Inject constructor( } fun checkStaleBGAlert() { - val bgReading = iobCobCalculatorPlugin.lastBg() + val bgReading = iobCobCalculator.lastBg() if (sp.getBoolean(R.string.key_enable_missed_bg_readings_alert, false) && bgReading != null && bgReading.timestamp + missedReadingsThreshold() < System.currentTimeMillis() && sp.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) { val n = Notification(Notification.BG_READINGS_MISSED, resourceHelper.gs(R.string.missed_bg_readings), Notification.URGENT) diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index 41789d524d..e6ed7f5a5a 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -22,7 +22,6 @@ import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage @@ -54,7 +53,7 @@ import java.util.* ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::class, - UserEntryLogger::class, IobCobCalculatorPlugin::class, LoggerUtils::class, AppRepository::class) + UserEntryLogger::class, LoggerUtils::class, AppRepository::class) class ConstraintsCheckerTest : TestBaseWithProfile() { @Mock lateinit var activePlugin: ActivePluginProvider diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt index 8869464e7b..5f6edae103 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt @@ -14,7 +14,11 @@ import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction -import info.nightscout.androidaps.interfaces.* +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker @@ -22,7 +26,6 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePas import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin @@ -55,7 +58,7 @@ import java.util.* @PrepareForTest( ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class, - IobCobCalculatorPlugin::class, OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class, + OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class, AppRepository::class, DateUtil::class) class SmsCommunicatorPluginTest : TestBaseWithProfile() { @@ -96,8 +99,6 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { val bgList: MutableList = ArrayList() bgList.add(reading) - `when`(iobCobCalculator.dataLock).thenReturn(Any()) - `when`(iobCobCalculator.bgReadings).thenReturn(bgList) `when`(iobCobCalculator.getCobInfo(false, "SMS COB")).thenReturn(CobInfo(10.0, 2.0)) `when`(iobCobCalculator.lastBg()).thenReturn(reading) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt index 66fd6a3112..36fb76d52e 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPluginTest.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator import android.content.Context +import android.os.PowerManager import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase @@ -22,6 +23,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.`when` import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner import java.util.* @@ -41,18 +43,25 @@ class IobCobCalculatorPluginTest : TestBase() { @Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var repository: AppRepository @Mock lateinit var context: Context + @Mock lateinit var powerManager: PowerManager lateinit var dateUtil: DateUtil - lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + private lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin val injector = HasAndroidInjector { AndroidInjector { + if (it is IobCobThread) { + it.context = context + it.resourceHelper = resourceHelper + } } } @Before fun mock() { dateUtil = DateUtil(context) + `when`(context.applicationContext).thenReturn(context) + `when`(context.getSystemService(anyObject())).thenReturn(powerManager) iobCobCalculatorPlugin = IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, activePlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) } diff --git a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt index dfca903165..e6420176ba 100644 --- a/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/utils/wizard/BolusWizardTest.kt @@ -12,7 +12,6 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil @@ -28,7 +27,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @RunWith(PowerMockRunner::class) -@PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, IobCobCalculatorPlugin::class, DateUtil::class) +@PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, DateUtil::class) class BolusWizardTest : TestBase() { private val pumpBolusStep = 0.1 @@ -71,7 +70,6 @@ class BolusWizardTest : TestBase() { `when`(profile.ic).thenReturn(insulinToCarbRatio) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) - `when`(iobCobCalculator.dataLock).thenReturn(Any()) `when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin) `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis())) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt index 83b8eb0e5b..41a898f06d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt @@ -38,7 +38,7 @@ abstract class Trigger(val injector: HasAndroidInjector) { @Inject lateinit var locationDataContainer: LastLocationDataContainer @Inject lateinit var repository: AppRepository @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculator + @Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @Inject lateinit var dateUtil: DateUtil diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt index 1cfb6c5b4c..f180d2f179 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.kt @@ -30,7 +30,7 @@ class TriggerAutosensValue(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val autosensData = iobCobCalculatorPlugin.getLastAutosensData("Automation trigger") + val autosensData = iobCobCalculator.getLastAutosensData("Automation trigger") ?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) true diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt index f561145eb9..dda052bcaf 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.kt @@ -38,7 +38,7 @@ class TriggerCOB(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "AutomationTriggerCOB") + val cobInfo = iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB") if (cobInfo.displayCob == null) { return if (comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt index a4e62d090e..4b407201ca 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.kt @@ -34,7 +34,7 @@ class TriggerIob(injector: HasAndroidInjector) : Trigger(injector) { override fun shouldRun(): Boolean { val profile = profileFunction.getProfile() ?: return false - val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(dateUtil.now(), profile) + val iob = iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(dateUtil.now(), profile) if (comparator.value.check(iob.iob, insulin.value)) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) return true diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt index a8c803c8ff..5b47242f5a 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValueTest.kt @@ -25,7 +25,7 @@ class TriggerAutosensValueTest : TriggerTestBase() { @Test fun shouldRunTest() { `when`(sp.getDouble(Mockito.eq(R.string.key_openapsama_autosens_max), ArgumentMatchers.anyDouble())).thenReturn(1.2) `when`(sp.getDouble(Mockito.eq(R.string.key_openapsama_autosens_min), ArgumentMatchers.anyDouble())).thenReturn(0.7) - `when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(generateAutosensData()) + `when`(iobCobCalculator.getLastAutosensData("Automation trigger")).thenReturn(generateAutosensData()) var t = TriggerAutosensValue(injector) t.autosens.value = 110.0 t.comparator.value = Comparator.Compare.IS_EQUAL @@ -65,14 +65,14 @@ class TriggerAutosensValueTest : TriggerTestBase() { t.autosens.value = 390.0 t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER Assert.assertTrue(t.shouldRun()) - PowerMockito.`when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(AutosensData(injector)) + PowerMockito.`when`(iobCobCalculator.getLastAutosensData("Automation trigger")).thenReturn(AutosensData(injector)) t = TriggerAutosensValue(injector) t.autosens.value = 80.0 t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER Assert.assertFalse(t.shouldRun()) // Test autosensData == null and Comparator == IS_NOT_AVAILABLE - PowerMockito.`when`(iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")).thenReturn(null) + PowerMockito.`when`(iobCobCalculator.getLastAutosensData("Automation trigger")).thenReturn(null) t = TriggerAutosensValue(injector) t.comparator.value = Comparator.Compare.IS_NOT_AVAILABLE Assert.assertTrue(t.shouldRun()) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt index fe0e9049ba..88d1aeec2c 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.kt @@ -26,13 +26,12 @@ class TriggerBgTest : TriggerTestBase() { @Before fun prepare() { `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Any()) `when`(dateUtil.now()).thenReturn(now) } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOneCurrentRecordBgData()) + `when`(iobCobCalculator.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData()) var t: TriggerBg = TriggerBg(injector).setUnits(Constants.MMOL).setValue(4.1).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(214.0).comparator(Comparator.Compare.IS_EQUAL) @@ -51,7 +50,7 @@ class TriggerBgTest : TriggerTestBase() { Assert.assertTrue(t.shouldRun()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(ArrayList()) + `when`(iobCobCalculator.getBgReadingsDataTableCopy()).thenReturn(ArrayList()) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) t = TriggerBg(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt index d194c50b1b..d67fb0a109 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOBTest.kt @@ -28,7 +28,7 @@ class TriggerCOBTest : TriggerTestBase() { @Test fun shouldRunTest() { // COB value is 6 - PowerMockito.`when`(iobCobCalculatorPlugin.getCobInfo(false, "AutomationTriggerCOB")).thenReturn(CobInfo(6.0, 2.0)) + PowerMockito.`when`(iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB")).thenReturn(CobInfo(6.0, 2.0)) var t: TriggerCOB = TriggerCOB(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt index 9a9107ec4b..a5d27e2ffe 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDeltaTest.kt @@ -20,7 +20,7 @@ import org.powermock.modules.junit4.PowerMockRunner import java.util.* @RunWith(PowerMockRunner::class) -@PrepareForTest(DateUtil::class, ProfileFunction::class) +@PrepareForTest(DateUtil::class, ProfileFunction::class) class TriggerDeltaTest : TriggerTestBase() { var now = 1514766900000L @@ -28,12 +28,11 @@ class TriggerDeltaTest : TriggerTestBase() { @Before fun mock() { PowerMockito.`when`(dateUtil.now()).thenReturn(now) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Any()) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateValidBgData()) + `when`(iobCobCalculator.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData()) var t = TriggerDelta(injector).units(Constants.MGDL).setValue(73.0, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) Assert.assertEquals(DeltaType.LONG_AVERAGE, t.delta.deltaType) @@ -55,7 +54,7 @@ class TriggerDeltaTest : TriggerTestBase() { Assert.assertFalse(t.shouldRun()) t = TriggerDelta(injector).units(Constants.MGDL).setValue(-0.2, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertTrue(t.shouldRun()) - `when`(iobCobCalculatorPlugin.bgReadings).thenReturn(ArrayList()) + `when`(iobCobCalculator.getBgReadingsDataTableCopy()).thenReturn(ArrayList()) t = TriggerDelta(injector).units(Constants.MGDL).setValue(213.0, DeltaType.DELTA).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertFalse(t.shouldRun()) t = TriggerDelta(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt index d013e2f9c4..b71c054975 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIobTest.kt @@ -27,7 +27,7 @@ class TriggerIobTest : TriggerTestBase() { } @Test fun shouldRunTest() { - `when`(iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(ArgumentMatchers.anyLong(), anyObject())).thenReturn(generateIobRecordData()) + `when`(iobCobCalculator.calculateFromTreatmentsAndTempsSynchronized(ArgumentMatchers.anyLong(), anyObject())).thenReturn(generateIobRecordData()) var t: TriggerIob = TriggerIob(injector).setValue(1.1).comparator(Comparator.Compare.IS_EQUAL) Assert.assertFalse(t.shouldRun()) t = TriggerIob(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt index 2dbca12360..2dbe5766fd 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTestBase.kt @@ -5,7 +5,6 @@ import dagger.android.AndroidInjector import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestPumpPlugin -import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.PluginDescription @@ -14,7 +13,6 @@ import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.services.LastLocationDataContainer -import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.sharedPreferences.SP import org.junit.Before import org.mockito.Mock @@ -27,7 +25,7 @@ open class TriggerTestBase : TestBaseWithProfile() { @Mock lateinit var sp: SP @Mock lateinit var locationDataContainer: LastLocationDataContainer @Mock lateinit var activePlugin: ActivePluginProvider - @Mock lateinit var iobCobCalculatorPlugin: IobCobCalculator + @Mock lateinit var iobCobCalculator: IobCobCalculator @Mock lateinit var context: Context @Mock lateinit var automationPlugin: AutomationPlugin @@ -53,8 +51,8 @@ open class TriggerTestBase : TestBaseWithProfile() { it.locationDataContainer = locationDataContainer it.repository = repository it.activePlugin = activePlugin - it.iobCobCalculatorPlugin = iobCobCalculatorPlugin - it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil) + it.iobCobCalculator = iobCobCalculator + it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculator, dateUtil) it.dateUtil = dateUtil } if (it is TriggerBg) { diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt index a7da3515ca..244e7ac82c 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/IobCobCalculator.kt @@ -17,25 +17,28 @@ import org.json.JSONArray interface IobCobCalculator { val dataLock: Any - var bgReadings: List - var bucketedData: MutableList? - val mealData: MealData + fun getBgReadingsDataTableCopy(): List + fun getBucketedDataTableCopy(): MutableList? fun getAutosensDataTable(): LongSparseArray - fun calculateIobArrayInDia(profile: Profile): Array + + + fun getMealDataWithWaitingForCalculationFinish(): MealData fun lastDataTime(): String fun getAutosensData(fromTime: Long): AutosensData? fun getLastAutosensData(reason: String): AutosensData? - fun getLastAutosensDataSynchronized(reason: String): AutosensData? + fun getLastAutosensDataWithWaitForCalculationFinish(reason: String): AutosensData? + + fun calculateIobArrayInDia(profile: Profile): Array fun calculateAbsInsulinFromTreatmentsAndTempsSynchronized(fromTime: Long): IobTotal fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile): IobTotal + fun getBasalData(profile: Profile, fromTime: Long): BasalData fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array fun iobArrayToString(array: Array): String fun slowAbsorptionPercentage(timeInMinutes: Int): Double fun convertToJSONArray(iobArray: Array): JSONArray - /** * Return last valid (>39) GlucoseValue from database or null if db is empty * @@ -46,11 +49,11 @@ interface IobCobCalculator { /** * Calculate CobInfo to now() * - * @param _synchronized access autosens data synchronized (wait for result if calculation is running) + * @param waitForCalculationFinish access autosens data synchronized (wait for result if calculation is running) * @param reason caller identification * @return CobInfo */ - fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo + fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo /** * Provide last GlucoseValue or null if none exists withing last 9 minutes @@ -97,7 +100,7 @@ interface IobCobCalculator { * * Running basal is added to the IOB !!! * - * @param timestamp + * @param toTime * @return IobTotal */ fun calculateAbsoluteIobTempBasals(toTime: Long): IobTotal @@ -105,7 +108,7 @@ interface IobCobCalculator { /** * Calculate IOB from Temporary basals and Extended boluses (if emulation is enabled) to the the time specified * - * @param time time to calculate to + * @param toTime time to calculate to * @return IobTotal */ fun calculateIobToTimeFromTempBasalsIncludingConvertedExtended(toTime: Long): IobTotal diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt index 544c1b4d9c..a11d5b372e 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/GlucoseStatusProvider.kt @@ -20,86 +20,84 @@ class GlucoseStatusProvider @Inject constructor( get() = getGlucoseStatusData() fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus? { - synchronized(iobCobCalculator.dataLock) { - val data = iobCobCalculator.bgReadings - val sizeRecords = data.size - if (sizeRecords == 0) { - aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0") - return null - } - if (data[0].timestamp < dateUtil.now() - 7 * 60 * 1000L && !allowOldData) { - aapsLogger.debug(LTag.GLUCOSE, "oldData") - return null - } - val now = data[0] - val nowDate = now.timestamp - var change: Double - if (sizeRecords == 1) { - aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1") - return GlucoseStatus( - glucose = now.value, - noise = 0.0, - delta = 0.0, - shortAvgDelta = 0.0, - longAvgDelta = 0.0, - date = nowDate - ).asRounded() - } - val nowValueList = ArrayList() - val lastDeltas = ArrayList() - val shortDeltas = ArrayList() - val longDeltas = ArrayList() - - // Use the latest sgv value in the now calculations - nowValueList.add(now.value) - for (i in 1 until sizeRecords) { - if (data[i].value > 38) { - val then = data[i] - val thenDate = then.timestamp - - val minutesAgo = ((nowDate - thenDate) / (1000.0 * 60)).roundToLong() - // multiply by 5 to get the same units as delta, i.e. mg/dL/5m - change = now.value - then.value - val avgDel = change / minutesAgo * 5 - aapsLogger.debug(LTag.GLUCOSE, "$then minutesAgo=$minutesAgo avgDelta=$avgDel") - - // use the average of all data points in the last 2.5m for all further "now" calculations - if (0 < minutesAgo && minutesAgo < 2.5) { - // Keep and average all values within the last 2.5 minutes - nowValueList.add(then.value) - now.value = average(nowValueList) - // short_deltas are calculated from everything ~5-15 minutes ago - } else if (2.5 < minutesAgo && minutesAgo < 17.5) { - //console.error(minutesAgo, avgDelta); - shortDeltas.add(avgDel) - // last_deltas are calculated from everything ~5 minutes ago - if (2.5 < minutesAgo && minutesAgo < 7.5) { - lastDeltas.add(avgDel) - } - // long_deltas are calculated from everything ~20-40 minutes ago - } else if (17.5 < minutesAgo && minutesAgo < 42.5) { - longDeltas.add(avgDel) - } else { - // Do not process any more records after >= 42.5 minutes - break - } - } - } - val shortAverageDelta = average(shortDeltas) - val delta = if (lastDeltas.isEmpty()) { - shortAverageDelta - } else { - average(lastDeltas) - } + val data = iobCobCalculator.getBgReadingsDataTableCopy() + val sizeRecords = data.size + if (sizeRecords == 0) { + aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0") + return null + } + if (data[0].timestamp < dateUtil.now() - 7 * 60 * 1000L && !allowOldData) { + aapsLogger.debug(LTag.GLUCOSE, "oldData") + return null + } + val now = data[0] + val nowDate = now.timestamp + var change: Double + if (sizeRecords == 1) { + aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==1") return GlucoseStatus( glucose = now.value, - date = nowDate, - noise = 0.0, //for now set to nothing as not all CGMs report noise - shortAvgDelta = shortAverageDelta, - delta = delta, - longAvgDelta = average(longDeltas), - ).also { aapsLogger.debug(LTag.GLUCOSE, it.log()) }.asRounded() + noise = 0.0, + delta = 0.0, + shortAvgDelta = 0.0, + longAvgDelta = 0.0, + date = nowDate + ).asRounded() } + val nowValueList = ArrayList() + val lastDeltas = ArrayList() + val shortDeltas = ArrayList() + val longDeltas = ArrayList() + + // Use the latest sgv value in the now calculations + nowValueList.add(now.value) + for (i in 1 until sizeRecords) { + if (data[i].value > 38) { + val then = data[i] + val thenDate = then.timestamp + + val minutesAgo = ((nowDate - thenDate) / (1000.0 * 60)).roundToLong() + // multiply by 5 to get the same units as delta, i.e. mg/dL/5m + change = now.value - then.value + val avgDel = change / minutesAgo * 5 + aapsLogger.debug(LTag.GLUCOSE, "$then minutesAgo=$minutesAgo avgDelta=$avgDel") + + // use the average of all data points in the last 2.5m for all further "now" calculations + if (0 < minutesAgo && minutesAgo < 2.5) { + // Keep and average all values within the last 2.5 minutes + nowValueList.add(then.value) + now.value = average(nowValueList) + // short_deltas are calculated from everything ~5-15 minutes ago + } else if (2.5 < minutesAgo && minutesAgo < 17.5) { + //console.error(minutesAgo, avgDelta); + shortDeltas.add(avgDel) + // last_deltas are calculated from everything ~5 minutes ago + if (2.5 < minutesAgo && minutesAgo < 7.5) { + lastDeltas.add(avgDel) + } + // long_deltas are calculated from everything ~20-40 minutes ago + } else if (17.5 < minutesAgo && minutesAgo < 42.5) { + longDeltas.add(avgDel) + } else { + // Do not process any more records after >= 42.5 minutes + break + } + } + } + val shortAverageDelta = average(shortDeltas) + val delta = if (lastDeltas.isEmpty()) { + shortAverageDelta + } else { + average(lastDeltas) + } + return GlucoseStatus( + glucose = now.value, + date = nowDate, + noise = 0.0, //for now set to nothing as not all CGMs report noise + shortAvgDelta = shortAverageDelta, + delta = delta, + longAvgDelta = average(longDeltas), + ).also { aapsLogger.debug(LTag.GLUCOSE, it.log()) }.asRounded() } companion object { diff --git a/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt index d443f2d603..1805936599 100644 --- a/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt +++ b/core/src/test/java/info/nightscout/androidaps/plugins/iob/iobCalculator/GlucoseStatusTest.kt @@ -13,7 +13,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` import org.powermock.api.mockito.PowerMockito import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.modules.junit4.PowerMockRunner @@ -41,7 +40,7 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateValidGlucoseStatus() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateValidBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData()) val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(-2.0, glucoseStatus.delta, 0.001) @@ -51,7 +50,7 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateMostRecentGlucoseStatus() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateMostRecentBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateMostRecentBgData()) val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2 Assert.assertEquals(-1.0, glucoseStatus.delta, 0.001) @@ -61,7 +60,7 @@ class GlucoseStatusTest : TestBase() { } @Test fun oneRecordShouldProduceZeroDeltas() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOneCurrentRecordBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData()) val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(0.0, glucoseStatus.delta, 0.001) @@ -71,19 +70,19 @@ class GlucoseStatusTest : TestBase() { } @Test fun insufficientDataShouldReturnNull() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateInsufficientBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateInsufficientBgData()) val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData Assert.assertEquals(null, glucoseStatus) } @Test fun oldDataShouldReturnNull() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData()) val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData Assert.assertEquals(null, glucoseStatus) } @Test fun returnOldDataIfAllowed() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData()) val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true) Assert.assertNotEquals(null, glucoseStatus) } @@ -93,7 +92,7 @@ class GlucoseStatusTest : TestBase() { } @Test fun calculateGlucoseStatusForLibreTestBgData() { - PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateLibreTestData()) + PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateLibreTestData()) val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! Assert.assertEquals(100.0, glucoseStatus.glucose, 0.001) // Assert.assertEquals(-10.0, glucoseStatus.delta, 0.001) @@ -105,7 +104,6 @@ class GlucoseStatusTest : TestBase() { @Before fun initMocking() { PowerMockito.`when`(dateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()) - `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Any()) } // [{"mgdl":214,"mills":1521895773113,"device":"xDrip-DexcomG5","direction":"Flat","filtered":191040,"unfiltered":205024,"noise":1,"rssi":100},{"mgdl":219,"mills":1521896073352,"device":"xDrip-DexcomG5","direction":"Flat","filtered":200160,"unfiltered":209760,"noise":1,"rssi":100},{"mgdl":222,"mills":1521896372890,"device":"xDrip-DexcomG5","direction":"Flat","filtered":207360,"unfiltered":212512,"noise":1,"rssi":100},{"mgdl":220,"mills":1521896673062,"device":"xDrip-DexcomG5","direction":"Flat","filtered":211488,"unfiltered":210688,"noise":1,"rssi":100},{"mgdl":193,"mills":1521896972933,"device":"xDrip-DexcomG5","direction":"Flat","filtered":212384,"unfiltered":208960,"noise":1,"rssi":100},{"mgdl":181,"mills":1521897273336,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":210592,"unfiltered":204320,"noise":1,"rssi":100},{"mgdl":176,"mills":1521897572875,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":206720,"unfiltered":197440,"noise":1,"rssi":100},{"mgdl":168,"mills":1521897872929,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":201024,"unfiltered":187904,"noise":1,"rssi":100},{"mgdl":161,"mills":1521898172814,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":193376,"unfiltered":178144,"noise":1,"rssi":100},{"mgdl":148,"mills":1521898472879,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":183264,"unfiltered":161216,"noise":1,"rssi":100},{"mgdl":139,"mills":1521898772862,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":170784,"unfiltered":148928,"noise":1,"rssi":100},{"mgdl":132,"mills":1521899072896,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":157248,"unfiltered":139552,"noise":1,"rssi":100},{"mgdl":125,"mills":1521899372834,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":144416,"unfiltered":129616.00000000001,"noise":1,"rssi":100},{"mgdl":128,"mills":1521899973456,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130240.00000000001,"unfiltered":133536,"noise":1,"rssi":100},{"mgdl":132,"mills":1521900573287,"device":"xDrip-DexcomG5","direction":"Flat","filtered":133504,"unfiltered":138720,"noise":1,"rssi":100},{"mgdl":127,"mills":1521900873711,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136480,"unfiltered":132992,"noise":1,"rssi":100},{"mgdl":127,"mills":1521901180151,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136896,"unfiltered":132128,"noise":1,"rssi":100},{"mgdl":125,"mills":1521901473582,"device":"xDrip-DexcomG5","direction":"Flat","filtered":134624,"unfiltered":129696,"noise":1,"rssi":100},{"mgdl":120,"mills":1521901773597,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130704.00000000001,"unfiltered":123376,"noise":1,"rssi":100},{"mgdl":116,"mills":1521902075855,"device":"xDrip-DexcomG5","direction":"Flat","filtered":126272,"unfiltered":118448,"noise":1,"rssi":100}]