cache last DataStore object for bolus wizard

This commit is contained in:
Milos Kozak 2023-01-12 10:44:01 +01:00
parent c802e7e4a2
commit 86edb3dfae
16 changed files with 95 additions and 42 deletions

View file

@ -32,11 +32,10 @@ interface IobCobCalculator {
/** /**
* Calculate CobInfo to now() * Calculate CobInfo to now()
* *
* @param waitForCalculationFinish access autosens data synchronized (wait for result if calculation is running)
* @param reason caller identification * @param reason caller identification
* @return CobInfo * @return CobInfo
*/ */
fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo fun getCobInfo(reason: String): CobInfo
/** /**
* Calculate IobTotal from boluses and extended boluses to now(). * Calculate IobTotal from boluses and extended boluses to now().

View file

@ -107,7 +107,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
fun isActive(): Boolean = time.secondsFromMidnight() >= validFrom() && time.secondsFromMidnight() <= validTo() && forDevice(DEVICE_PHONE) fun isActive(): Boolean = time.secondsFromMidnight() >= validFrom() && time.secondsFromMidnight() <= validTo() && forDevice(DEVICE_PHONE)
fun doCalc(profile: Profile, profileName: String, lastBG: InMemoryGlucoseValue, _synchronized: Boolean): BolusWizard { fun doCalc(profile: Profile, profileName: String, lastBG: InMemoryGlucoseValue): BolusWizard {
val dbRecord = persistenceLayer.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() val dbRecord = persistenceLayer.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
//BG //BG
@ -117,7 +117,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
} }
// COB // COB
val cob = val cob =
if (useCOB() == YES) iobCobCalculator.getCobInfo(_synchronized, "QuickWizard COB").displayCob ?: 0.0 if (useCOB() == YES) iobCobCalculator.getCobInfo("QuickWizard COB").displayCob ?: 0.0
else 0.0 else 0.0
// Bolus IOB // Bolus IOB
var bolusIOB = false var bolusIOB = false

View file

@ -219,7 +219,7 @@ class OverviewDataImpl @Inject constructor(
override fun bolusIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromBolus().round() override fun bolusIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromBolus().round()
override fun basalIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() override fun basalIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
override fun cobInfo(iobCobCalculator: IobCobCalculator): CobInfo = iobCobCalculator.getCobInfo(true, "Overview COB") override fun cobInfo(iobCobCalculator: IobCobCalculator): CobInfo = iobCobCalculator.getCobInfo("Overview COB")
override val lastCarbsTime: Long override val lastCarbsTime: Long
get() = repository.getLastCarbsRecordWrapped().blockingGet().let { lastCarbs -> get() = repository.getLastCarbsRecordWrapped().blockingGet().let { lastCarbs ->

View file

@ -38,7 +38,7 @@ class TriggerCOB(injector: HasAndroidInjector) : Trigger(injector) {
} }
override fun shouldRun(): Boolean { override fun shouldRun(): Boolean {
val cobInfo = iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB") val cobInfo = iobCobCalculator.getCobInfo("AutomationTriggerCOB")
if (cobInfo.displayCob == null) { if (cobInfo.displayCob == null) {
return if (comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) { return if (comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())

View file

@ -21,7 +21,7 @@ class TriggerCOBTest : TriggerTestBase() {
@Test fun shouldRunTest() { @Test fun shouldRunTest() {
// COB value is 6 // COB value is 6
`when`(iobCobCalculator.getCobInfo(false, "AutomationTriggerCOB")).thenReturn(CobInfo(0, 6.0, 2.0)) `when`(iobCobCalculator.getCobInfo("AutomationTriggerCOB")).thenReturn(CobInfo(0, 6.0, 2.0))
var t: TriggerCOB = TriggerCOB(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) var t: TriggerCOB = TriggerCOB(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL) t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL)

View file

@ -133,7 +133,7 @@ class DataBroadcastPlugin @Inject constructor(
bundle.putDouble("basalIob", basalIob.basaliob) bundle.putDouble("basalIob", basalIob.basaliob)
bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB bundle.putDouble("iob", bolusIob.iob + basalIob.basaliob) // total IOB
val cob = iobCobCalculator.getCobInfo(false, "broadcast") val cob = iobCobCalculator.getCobInfo("broadcast")
bundle.putDouble("cob", cob.displayCob ?: -1.0) // COB [g] or -1 if N/A bundle.putDouble("cob", cob.displayCob ?: -1.0) // COB [g] or -1 if N/A
bundle.putDouble("futureCarbs", cob.futureCarbs) // future scheduled carbs bundle.putDouble("futureCarbs", cob.futureCarbs) // future scheduled carbs
} }

View file

@ -511,7 +511,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val quickWizardEntry = quickWizard.getActive() val quickWizardEntry = quickWizard.getActive()
if (quickWizardEntry != null && actualBg != null && profile != null) { if (quickWizardEntry != null && actualBg != null && profile != null) {
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true) val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg)
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) { if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value() val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
activity?.let { activity?.let {
@ -539,7 +539,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
_binding ?: return@runOnUiThread _binding ?: return@runOnUiThread
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended() && !loop.isDisconnected) { if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended() && !loop.isDisconnected) {
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false) val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG)
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + rh.gs(info.nightscout.core.graph.R.string.format_carbs, quickWizardEntry.carbs()) + binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + rh.gs(info.nightscout.core.graph.R.string.format_carbs, quickWizardEntry.carbs()) +
" " + rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, wizard.calculatedTotalInsulin) " " + rh.gs(info.nightscout.interfaces.R.string.format_insulin_units, wizard.calculatedTotalInsulin)
if (wizard.calculatedTotalInsulin <= 0) binding.buttonsLayout.quickWizardButton.visibility = View.GONE if (wizard.calculatedTotalInsulin <= 0) binding.buttonsLayout.quickWizardButton.visibility = View.GONE

View file

@ -148,12 +148,10 @@ class PersistentNotificationPlugin @Inject constructor(
val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
line2 = line2 =
rh.gs(info.nightscout.core.ui.R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + rh.gs(info.nightscout.core.ui.R.string.cob) + ": " + iobCobCalculator.getCobInfo( rh.gs(info.nightscout.core.ui.R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + rh.gs(info.nightscout.core.ui.R.string.cob) + ": " + iobCobCalculator.getCobInfo(
false,
"PersistentNotificationPlugin" "PersistentNotificationPlugin"
).generateCOBString() ).generateCOBString()
val line2aa = val line2aa =
rh.gs(info.nightscout.core.ui.R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + rh.gs(info.nightscout.core.ui.R.string.cob) + ": " + iobCobCalculator.getCobInfo( rh.gs(info.nightscout.core.ui.R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + rh.gs(info.nightscout.core.ui.R.string.cob) + ": " + iobCobCalculator.getCobInfo(
false,
"PersistentNotificationPlugin" "PersistentNotificationPlugin"
).generateCOBString() + "." ).generateCOBString() + "."
line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h" line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h"

View file

@ -365,7 +365,7 @@ class SmsCommunicatorPlugin @Inject constructor(
if (glucoseStatus != null) reply += rh.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", " if (glucoseStatus != null) reply += rh.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
val bolusIob = iobCobCalculator.calculateIobFromBolus().round() val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
val cobInfo = iobCobCalculator.getCobInfo(false, "SMS COB") val cobInfo = iobCobCalculator.getCobInfo("SMS COB")
reply += (rh.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" reply += (rh.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U ("
+ rh.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U " + rh.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U "
+ rh.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), " + rh.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), "

View file

@ -16,7 +16,13 @@ import info.nightscout.core.wizard.BolusWizard
import info.nightscout.core.wizard.QuickWizard import info.nightscout.core.wizard.QuickWizard
import info.nightscout.core.wizard.QuickWizardEntry import info.nightscout.core.wizard.QuickWizardEntry
import info.nightscout.database.ValueWrapper import info.nightscout.database.ValueWrapper
import info.nightscout.database.entities.* import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.TemporaryBasal
import info.nightscout.database.entities.TemporaryTarget
import info.nightscout.database.entities.TotalDailyDose
import info.nightscout.database.entities.UserEntry
import info.nightscout.database.entities.ValueWithUnit
import info.nightscout.database.entities.interfaces.end import info.nightscout.database.entities.interfaces.end
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.database.impl.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
@ -60,7 +66,9 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.LinkedList
import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.stream.Collectors import java.util.stream.Collectors
import javax.inject.Inject import javax.inject.Inject
@ -369,7 +377,7 @@ class DataHandlerMobile @Inject constructor(
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_actual_bg)) sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_actual_bg))
return return
} }
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear") val cobInfo = iobCobCalculator.getCobInfo("Wizard wear")
if (cobInfo.displayCob == null) { if (cobInfo.displayCob == null) {
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_cob)) sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_cob))
return return
@ -436,7 +444,7 @@ class DataHandlerMobile @Inject constructor(
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_active_profile)) sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_active_profile))
return return
} }
val cobInfo = iobCobCalculator.getCobInfo(false, "QuickWizard wear") val cobInfo = iobCobCalculator.getCobInfo("QuickWizard wear")
if (cobInfo.displayCob == null) { if (cobInfo.displayCob == null) {
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_cob)) sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_no_cob))
return return
@ -447,7 +455,7 @@ class DataHandlerMobile @Inject constructor(
return return
} }
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true) val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg)
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value() val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
if (carbsAfterConstraints != quickWizardEntry.carbs()) { if (carbsAfterConstraints != quickWizardEntry.carbs()) {
@ -877,7 +885,7 @@ class DataHandlerMobile @Inject constructor(
val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round() val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob)
iobDetail = "(${DecimalFormatter.to2Decimal(bolusIob.iob)}|${DecimalFormatter.to2Decimal(basalIob.basaliob)})" iobDetail = "(${DecimalFormatter.to2Decimal(bolusIob.iob)}|${DecimalFormatter.to2Decimal(basalIob.basaliob)})"
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString() cobString = iobCobCalculator.getCobInfo("WatcherUpdaterService").generateCOBString()
currentBasal = currentBasal =
iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())?.toStringShort() ?: rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, profile.getBasal()) iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())?.toStringShort() ?: rh.gs(info.nightscout.core.ui.R.string.pump_base_basal_rate, profile.getBasal())

View file

@ -151,7 +151,7 @@ class StatusLinePlugin @Inject constructor(
status += " " + (if (bgi >= 0) "+" else "") + DecimalFormatter.to2Decimal(bgi) status += " " + (if (bgi >= 0) "+" else "") + DecimalFormatter.to2Decimal(bgi)
} }
// COB // COB
status += " " + iobCobCalculator.getCobInfo(false, "StatusLinePlugin").generateCOBString() status += " " + iobCobCalculator.getCobInfo("StatusLinePlugin").generateCOBString()
return status return status
} }
} }

View file

@ -292,10 +292,8 @@ class IobCobCalculatorPlugin @Inject constructor(
return ads.getLastAutosensData(reason, aapsLogger, dateUtil) return ads.getLastAutosensData(reason, aapsLogger, dateUtil)
} }
override fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo { override fun getCobInfo(reason: String): CobInfo {
val autosensData = val autosensData = ads.getLastAutosensData(reason, aapsLogger, dateUtil)
if (waitForCalculationFinish) getLastAutosensDataWithWaitForCalculationFinish(reason)
else ads.getLastAutosensData(reason, aapsLogger, dateUtil)
var displayCob: Double? = null var displayCob: Double? = null
var futureCarbs = 0.0 var futureCarbs = 0.0
val now = dateUtil.now() val now = dateUtil.now()

View file

@ -116,30 +116,34 @@ class AutosensDataStoreObject : AutosensDataStore {
} }
} }
// during recalculation autosensDataTable is cleared and not available
// for providing COB, which is an serious issue in BolusWizard
// So let save last value after every calculation and use it
// if autosensDataTable is not available
var storedLastAutosensResult: AutosensData? = null
get() = field?.let { if (it.time < System.currentTimeMillis() - 11 * 60 * 1000) it else null }
override fun getLastAutosensData(reason: String, aapsLogger: AAPSLogger, dateUtil: DateUtil): AutosensData? { override fun getLastAutosensData(reason: String, aapsLogger: AAPSLogger, dateUtil: DateUtil): AutosensData? {
synchronized(dataLock) { synchronized(dataLock) {
if (autosensDataTable.size() < 1) { if (autosensDataTable.size() < 1) {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty ($reason)") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: autosensDataTable empty ($reason)")
return null return storedLastAutosensResult
} }
val data: AutosensData? = try { val data: AutosensData = try {
autosensDataTable.valueAt(autosensDataTable.size() - 1) autosensDataTable.valueAt(autosensDataTable.size() - 1)
} catch (e: Exception) { } catch (e: Exception) {
// data can be processed on the background // data can be processed on the background
// in this rare case better return null and do not block UI // in this rare case better return null and do not block UI
// APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue // APS plugin should use getLastAutosensDataSynchronized where the blocking is not an issue
aapsLogger.error("AUTOSENSDATA null: Exception caught ($reason)") aapsLogger.error("AUTOSENSDATA null: Exception caught ($reason)")
return null return storedLastAutosensResult
} }
if (data == null) { return if (data.time < dateUtil.now() - 11 * 60 * 1000) {
aapsLogger.error("AUTOSENSDATA null: data==null")
return null
}
return if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA null: data is old ($reason) size()=${autosensDataTable.size()} lastData=${dateUtil.dateAndTimeAndSecondsString(data.time)}" } aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA null: data is old ($reason) size()=${autosensDataTable.size()} lastData=${dateUtil.dateAndTimeAndSecondsString(data.time)}" }
null storedLastAutosensResult
} else { } else {
aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA ($reason) $data" } aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA ($reason) $data" }
storedLastAutosensResult = data
data data
} }
} }
@ -152,11 +156,8 @@ class AutosensDataStoreObject : AutosensDataStore {
} }
var diff = abs(someTime - referenceTime) var diff = abs(someTime - referenceTime)
diff %= T.mins(5).msecs() diff %= T.mins(5).msecs()
if (diff > T.mins(2).plus(T.secs(30)).msecs()){ return if (diff > T.mins(2).plus(T.secs(30)).msecs()) someTime + abs(diff - T.mins(5).msecs()) // Adjust to the future
return someTime + abs(diff - T.mins(5).msecs()) // Adjust to the future else someTime - diff // adjust to the past
} else {
return someTime - diff // adjust to the past
}
} }
fun isAbout5minData(aapsLogger: AAPSLogger): Boolean { fun isAbout5minData(aapsLogger: AAPSLogger): Boolean {

View file

@ -97,7 +97,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
val bgList: MutableList<GlucoseValue> = ArrayList() val bgList: MutableList<GlucoseValue> = ArrayList()
bgList.add(reading) bgList.add(reading)
`when`(iobCobCalculator.getCobInfo(false, "SMS COB")).thenReturn(CobInfo(0, 10.0, 2.0)) `when`(iobCobCalculator.getCobInfo("SMS COB")).thenReturn(CobInfo(0, 10.0, 2.0))
`when`(iobCobCalculator.ads).thenReturn(autosensDataStore) `when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
`when`(autosensDataStore.lastBg()).thenReturn(InMemoryGlucoseValue(reading)) `when`(autosensDataStore.lastBg()).thenReturn(InMemoryGlucoseValue(reading))

View file

@ -1,22 +1,48 @@
package info.nightscout.plugins.iob package info.nightscout.plugins.iob
import android.content.Context import android.content.Context
import androidx.collection.LongSparseArray
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.database.entities.GlucoseValue import info.nightscout.database.entities.GlucoseValue
import info.nightscout.interfaces.aps.AutosensData
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataObject
import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataStoreObject
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito
class AutosensDataStoreTest : TestBase() { class AutosensDataStoreTest : TestBase() {
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var sp: SP
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var dateUtilMocked: DateUtil
private lateinit var dateUtil: DateUtil private lateinit var dateUtil: DateUtil
private val autosensDataStore = info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataStoreObject() private val autosensDataStore = AutosensDataStoreObject()
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is AutosensDataObject) {
it.aapsLogger = aapsLogger
it.sp = sp
it.rh = rh
it.profileFunction = profileFunction
it.dateUtil = dateUtilMocked
}
}
}
@BeforeEach @BeforeEach
fun mock() { fun mock() {
@ -1264,7 +1290,7 @@ class AutosensDataStoreTest : TestBase() {
Assertions.assertEquals(67.0, autosensDataStore.bucketedData!![3].value, 1.0) // Recalculated data to 30min Assertions.assertEquals(67.0, autosensDataStore.bucketedData!![3].value, 1.0) // Recalculated data to 30min
Assertions.assertEquals(45.0, autosensDataStore.bucketedData!![5].value, 1.0) // Recalculated data to 20min Assertions.assertEquals(45.0, autosensDataStore.bucketedData!![5].value, 1.0) // Recalculated data to 20min
// non 5min data without referenceTime set, should allign the data to the time of the last reading // non 5min data without referenceTime set, should align the data to the time of the last reading
autosensDataStore.referenceTime = -1 autosensDataStore.referenceTime = -1
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add( bgReadingList.add(
@ -1491,4 +1517,27 @@ class AutosensDataStoreTest : TestBase() {
Assertions.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(20).msecs())) Assertions.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(20).msecs()))
Assertions.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(25).msecs())) Assertions.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(25).msecs()))
} }
@Test
fun getLastAutosensDataTest() {
val now = 10000000L
Mockito.`when`(dateUtilMocked.now()).thenReturn(now)
val ads = AutosensDataStoreObject()
ads.storedLastAutosensResult = AutosensDataObject(injector).apply { time = now - 10 }
// empty array, return last stored
ads.autosensDataTable = LongSparseArray<AutosensData>()
Assertions.assertEquals(now - 10, ads.getLastAutosensData("test", aapsLogger, dateUtilMocked)?.time)
// data is there, return it
ads.autosensDataTable.append(now - 1, AutosensDataObject(injector).apply { time = now - 1 })
Assertions.assertEquals(now - 1, ads.getLastAutosensData("test", aapsLogger, dateUtilMocked)?.time)
// and latest value should be saved
Assertions.assertEquals(now - 1, ads.storedLastAutosensResult?.time)
// data is old, return last stored
ads.storedLastAutosensResult = AutosensDataObject(injector).apply { time = now - 1 }
ads.autosensDataTable = LongSparseArray<AutosensData>()
ads.autosensDataTable.append(now - T.mins(20).msecs(), AutosensDataObject(injector).apply { time = now - T.mins(20).msecs() })
Assertions.assertEquals(now - 1, ads.getLastAutosensData("test", aapsLogger, dateUtilMocked)?.time)
}
} }

View file

@ -434,7 +434,7 @@ class WizardDialog : DaggerDialogFragment() {
// COB // COB
var cob = 0.0 var cob = 0.0
if (binding.cobCheckbox.isChecked) { if (binding.cobCheckbox.isChecked) {
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard COB") val cobInfo = iobCobCalculator.getCobInfo("Wizard COB")
cobInfo.displayCob?.let { cob = it } cobInfo.displayCob?.let { cob = it }
} }