From 845879d91635c788f18b73382f1f567a253e37fd Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Thu, 9 Jun 2022 15:22:02 +0200 Subject: [PATCH] Cache TDD calculations --- .../nightscout/androidaps/MainActivity.kt | 1 - .../IobCobCalculatorPlugin.kt | 46 ++-- .../androidaps/utils/stats/TddCalculator.kt | 110 ++++---- .../plugins/pump/common/defs/PumpType.kt | 255 +++++++++++------- .../androidaps/database/AppRepository.kt | 21 +- .../database/daos/TotalDailyDoseDao.kt | 14 +- .../database/embedments/InterfaceIDs.kt | 3 +- 7 files changed, 261 insertions(+), 189 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index e4960d913f..e3c7fb1c11 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -39,7 +39,6 @@ import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.logging.UserEntryLogger -import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils 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 6d76621a6d..00fa1dd6dd 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 @@ -30,6 +30,7 @@ import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.workflow.CalculationWorkflow import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP @@ -127,10 +128,20 @@ class IobCobCalculatorPlugin @Inject constructor( } private fun resetDataAndRunCalculation(reason: String, event: Event?) { - calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,reason) + calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION, reason) clearCache() ads.reset() - calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event, runLoop = true) + calculationWorkflow.runCalculation( + CalculationWorkflow.MAIN_CALCULATION, + this, + overviewData, + reason, + System.currentTimeMillis(), + bgDataReload = false, + limitDataToOldestAvailable = true, + cause = event, + runLoop = true + ) } override fun clearCache() { @@ -363,18 +374,21 @@ class IobCobCalculatorPlugin @Inject constructor( scheduledHistoryPost?.cancel(false) // prepare task for execution in 1 sec scheduledEvent = event - scheduledHistoryPost = historyWorker.schedule({ - synchronized(this) { - aapsLogger.debug(LTag.AUTOSENS, "Running newHistoryData") - newHistoryData( - event.oldDataTimestamp, - event.reloadBgData, - if (event.newestGlucoseValue != null) EventNewBG(event.newestGlucoseValue) else event - ) - scheduledEvent = null - scheduledHistoryPost = null - } - }, 1L, TimeUnit.SECONDS) + scheduledHistoryPost = historyWorker.schedule( + { + synchronized(this) { + aapsLogger.debug(LTag.AUTOSENS, "Running newHistoryData") + repository.clearCachedData(MidnightTime.calc(event.oldDataTimestamp)) + newHistoryData( + event.oldDataTimestamp, + event.reloadBgData, + if (event.newestGlucoseValue != null) EventNewBG(event.newestGlucoseValue) else event + ) + scheduledEvent = null + scheduledHistoryPost = null + } + }, 1L, TimeUnit.SECONDS + ) } else { // asked reload is newer -> adjust params only scheduledEvent?.let { @@ -391,7 +405,7 @@ class IobCobCalculatorPlugin @Inject constructor( // When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated private fun newHistoryData(oldDataTimestamp: Long, bgDataReload: Boolean, event: Event) { //log.debug("Locking onNewHistoryData"); - calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,"onEventNewHistoryData") + calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION, "onEventNewHistoryData") synchronized(dataLock) { // clear up 5 min back for proper COB calculation @@ -415,7 +429,7 @@ class IobCobCalculatorPlugin @Inject constructor( } ads.newHistoryData(time, aapsLogger, dateUtil) } - calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event, runLoop = true) + calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION, this, overviewData, event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event, runLoop = true) //log.debug("Releasing onNewHistoryData"); } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt index 91ef25a1f8..e6261c5e37 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt @@ -11,6 +11,8 @@ import android.widget.TableRow import android.widget.TextView import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.ValueWrapper +import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.TotalDailyDose import info.nightscout.androidaps.extensions.convertedToAbsolute @@ -19,10 +21,10 @@ import info.nightscout.androidaps.extensions.toTableRowHeader import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import javax.inject.Inject @@ -38,48 +40,62 @@ class TddCalculator @Inject constructor( ) { fun calculate(days: Long): LongSparseArray { - val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) + var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) val endTime = MidnightTime.calc(dateUtil.now()) val result = LongSparseArray() - repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() - .filter { it.type != Bolus.Type.PRIMING } - .forEach { t -> - val midnight = MidnightTime.calc(t.timestamp) - val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) - tdd.bolusAmount += t.amount - result.put(midnight, tdd) - } - repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t -> - val midnight = MidnightTime.calc(t.timestamp) - val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) - tdd.carbs += t.amount - result.put(midnight, tdd) + // Try to load cached values + while (startTime < endTime) { + val tdd = repository.getCalculatedTotalDailyDose(startTime).blockingGet() + if (tdd is ValueWrapper.Existing) result.put(startTime, tdd.value) + else break + startTime += T.hours(24).msecs() } - val calculationStep = T.mins(5).msecs() - val tempBasals = iobCobCalculator.getTempBasalIncludingConvertedExtendedForRange(startTime, endTime, calculationStep) - for (t in startTime until endTime step calculationStep) { - val midnight = MidnightTime.calc(t) - val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) - val tbr = tempBasals[t] - val profile = profileFunction.getProfile(t) ?: continue - val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) - tdd.basalAmount += absoluteRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble() - - if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { - // they are not included in TBRs - val eb = iobCobCalculator.getExtendedBolus(t) - val absoluteEbRate = eb?.rate ?: 0.0 - tdd.bolusAmount += absoluteEbRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble() + if (endTime > startTime) { + repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() + .filter { it.type != Bolus.Type.PRIMING } + .forEach { t -> + val midnight = MidnightTime.calc(t.timestamp) + val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) + tdd.bolusAmount += t.amount + result.put(midnight, tdd) + } + repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t -> + val midnight = MidnightTime.calc(t.timestamp) + val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) + tdd.carbs += t.amount + result.put(midnight, tdd) + } + + val calculationStep = T.mins(5).msecs() + val tempBasals = iobCobCalculator.getTempBasalIncludingConvertedExtendedForRange(startTime, endTime, calculationStep) + for (t in startTime until endTime step calculationStep) { + val midnight = MidnightTime.calc(t) + val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) + val tbr = tempBasals[t] + val profile = profileFunction.getProfile(t) ?: continue + val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) + tdd.basalAmount += absoluteRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble() + + if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { + // they are not included in TBRs + val eb = iobCobCalculator.getExtendedBolus(t) + val absoluteEbRate = eb?.rate ?: 0.0 + tdd.bolusAmount += absoluteEbRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble() + } + result.put(midnight, tdd) } - result.put(midnight, tdd) } for (i in 0 until result.size()) { val tdd = result.valueAt(i) tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount + if (tdd.interfaceIDs.pumpType != InterfaceIDs.PumpType.CACHE) { + tdd.interfaceIDs.pumpType = InterfaceIDs.PumpType.CACHE + aapsLogger.debug(LTag.CORE, "Storing TDD $tdd") + repository.createTotalDailyDose(tdd) + } } - aapsLogger.debug(LTag.CORE, result.toString()) return result } @@ -91,22 +107,13 @@ class TddCalculator @Inject constructor( repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() .filter { it.type != Bolus.Type.PRIMING } .forEach { t -> - //val midnight = MidnightTime.calc(t.timestamp) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) tdd.bolusAmount += t.amount - //result.put(midnight, tdd) } repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t -> - //val midnight = MidnightTime.calc(t.timestamp) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) tdd.carbs += t.amount - //result.put(midnight, tdd) } val calculationStep = T.mins(5).msecs() for (t in startTime until endTime step calculationStep) { - - //val midnight = MidnightTime.calc(t) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t) val profile = profileFunction.getProfile(t) ?: continue val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) @@ -118,13 +125,8 @@ class TddCalculator @Inject constructor( val absoluteEbRate = eb?.rate ?: 0.0 tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0 } - //result.put(midnight, tdd) } - //for (i in 0 until tdd.size()) { - //val tdd = result.valueAt(i) tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount - //} - aapsLogger.debug(LTag.CORE, tdd.toString()) return tdd } @@ -133,27 +135,16 @@ class TddCalculator @Inject constructor( val startTime = dateUtil.now() - T.hours(hour = 24).msecs() val endTime = dateUtil.now() val tdd = TotalDailyDose(timestamp = startTime) - //val result = TotalDailyDose() repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() .filter { it.type != Bolus.Type.PRIMING } .forEach { t -> - //val midnight = MidnightTime.calc(t.timestamp) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) tdd.bolusAmount += t.amount - //result.put(midnight, tdd) } repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t -> - //val midnight = MidnightTime.calc(t.timestamp) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) tdd.carbs += t.amount - //result.put(midnight, tdd) } val calculationStep = T.mins(5).msecs() - //val tempBasals = iobCobCalculator.getTempBasalIncludingConvertedExtendedForRange(startTime, endTime, calculationStep) for (t in startTime until endTime step calculationStep) { - - //val midnight = MidnightTime.calc(t) - //val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight) val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t) val profile = profileFunction.getProfile(t) ?: continue val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) @@ -165,13 +156,8 @@ class TddCalculator @Inject constructor( val absoluteEbRate = eb?.rate ?: 0.0 tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0 } - //result.put(midnight, tdd) } - //for (i in 0 until tdd.size()) { - //val tdd = result.valueAt(i) tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount - //} - aapsLogger.debug(LTag.CORE, tdd.toString()) return tdd } diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt index 9344476a61..0a9d28d76c 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpType.kt @@ -11,7 +11,8 @@ import kotlin.math.min @Suppress("unused") enum class PumpType { - GENERIC_AAPS(description = "Generic AAPS", + GENERIC_AAPS( + description = "Generic AAPS", manufacturer = ManufacturerType.AndroidAPS, model = "VirtualPump", bolusSize = 0.1, @@ -23,9 +24,11 @@ enum class PumpType { baseBasalMinValue = 0.01, baseBasalStep = 0.01, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.VirtualPumpCapabilities), + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), - CELLNOVO(description = "Cellnovo", + CELLNOVO( + description = "Cellnovo", manufacturer = ManufacturerType.Cellnovo, model = "Cellnovo", bolusSize = 0.05, @@ -37,9 +40,11 @@ enum class PumpType { baseBasalMinValue = 0.05, baseBasalStep = 0.05, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.VirtualPumpCapabilities), + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), - ACCU_CHEK_COMBO(description = "Accu-Chek Combo", + ACCU_CHEK_COMBO( + description = "Accu-Chek Combo", manufacturer = ManufacturerType.Roche, model = "Combo", bolusSize = 0.1, @@ -53,8 +58,10 @@ enum class PumpType { baseBasalSpecialSteps = DoseStepSize.ComboBasal, pumpCapability = PumpCapability.ComboCapabilities, source = Sources.Combo, - supportBatteryLevel = false), - ACCU_CHEK_SPIRIT(description = "Accu-Chek Spirit", + supportBatteryLevel = false + ), + ACCU_CHEK_SPIRIT( + description = "Accu-Chek Spirit", manufacturer = ManufacturerType.Roche, model = "Spirit", bolusSize = 0.1, @@ -66,8 +73,10 @@ enum class PumpType { baseBasalMinValue = 0.01, baseBasalStep = 0.1, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.VirtualPumpCapabilities), - ACCU_CHEK_INSIGHT_VIRTUAL(description = "Accu-Chek Insight", + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), + ACCU_CHEK_INSIGHT_VIRTUAL( + description = "Accu-Chek Insight", manufacturer = ManufacturerType.Roche, model = "Insight", bolusSize = 0.05, @@ -79,8 +88,10 @@ enum class PumpType { baseBasalMinValue = 0.02, baseBasalStep = 0.01, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.InsightCapabilities), - ACCU_CHEK_INSIGHT(description = "Accu-Chek Insight", + pumpCapability = PumpCapability.InsightCapabilities + ), + ACCU_CHEK_INSIGHT( + description = "Accu-Chek Insight", manufacturer = ManufacturerType.Roche, model = "Insight", bolusSize = 0.01, @@ -94,8 +105,10 @@ enum class PumpType { baseBasalStep = 0.01, baseBasalSpecialSteps = DoseStepSize.InsightBasal, pumpCapability = PumpCapability.InsightCapabilities, - source = Sources.Insight), - ACCU_CHEK_SOLO(description = "Accu-Chek Solo", + source = Sources.Insight + ), + ACCU_CHEK_SOLO( + description = "Accu-Chek Solo", manufacturer = ManufacturerType.Roche, model = "Solo", bolusSize = 0.01, @@ -108,9 +121,11 @@ enum class PumpType { baseBasalMaxValue = null, baseBasalStep = 0.01, baseBasalSpecialSteps = DoseStepSize.InsightBolus, - pumpCapability = PumpCapability.InsightCapabilities), + pumpCapability = PumpCapability.InsightCapabilities + ), - ANIMAS_VIBE(description = "Animas Vibe", + ANIMAS_VIBE( + description = "Animas Vibe", manufacturer = ManufacturerType.Animas, model = "Vibe", bolusSize = 0.05, @@ -123,9 +138,11 @@ enum class PumpType { baseBasalMaxValue = 5.0, baseBasalStep = 0.0, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.VirtualPumpCapabilities), + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), ANIMAS_PING(description = "Animas Ping", model = "Ping", parent = ANIMAS_VIBE), - DANA_R(description = "DanaR", + DANA_R( + description = "DanaR", manufacturer = ManufacturerType.Sooil, model = "DanaR", bolusSize = 0.05, @@ -138,8 +155,10 @@ enum class PumpType { baseBasalStep = 0.01, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.DanaCapabilities, - source = Sources.DanaR), - DANA_R_KOREAN(description = "DanaR Korean", + source = Sources.DanaR + ), + DANA_R_KOREAN( + description = "DanaR Korean", manufacturer = ManufacturerType.Sooil, model = "DanaRKorean", bolusSize = 0.05, @@ -152,8 +171,10 @@ enum class PumpType { baseBasalStep = 0.01, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.DanaCapabilities, - source = Sources.DanaRC), - DANA_RS(description = "DanaRS", + source = Sources.DanaRC + ), + DANA_RS( + description = "DanaRS", manufacturer = ManufacturerType.Sooil, model = "DanaRS", bolusSize = 0.05, @@ -166,11 +187,13 @@ enum class PumpType { baseBasalStep = 0.01, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.DanaWithHistoryCapabilities, - source = Sources.DanaRS), + source = Sources.DanaRS + ), DANA_RS_KOREAN(description = "DanaRSKorean", model = "DanaRSKorean", parent = DANA_RS), DANA_I(description = "DanaI", model = "DanaI", parent = DANA_RS, source = Sources.DanaI), DANA_RV2(description = "DanaRv2", model = "DanaRv2", parent = DANA_RS, source = Sources.DanaRv2), - OMNIPOD_EROS(description = "Omnipod Eros", + OMNIPOD_EROS( + description = "Omnipod Eros", manufacturer = ManufacturerType.Insulet, model = "Eros", bolusSize = 0.05, @@ -188,8 +211,10 @@ enum class PumpType { isPatchPump = true, useHardwareLink = true, supportBatteryLevel = false, - source = Sources.OmnipodEros), - OMNIPOD_DASH(description = "Omnipod Dash", + source = Sources.OmnipodEros + ), + OMNIPOD_DASH( + description = "Omnipod Dash", manufacturer = ManufacturerType.Insulet, model = "Dash", bolusSize = 0.05, @@ -205,8 +230,10 @@ enum class PumpType { isPatchPump = true, pumpCapability = PumpCapability.OmnipodCapabilities, hasCustomUnreachableAlertCheck = false, - supportBatteryLevel = false), - MEDTRONIC_512_712(description = "Medtronic 512/712", + supportBatteryLevel = false + ), + MEDTRONIC_512_712( + description = "Medtronic 512/712", manufacturer = ManufacturerType.Medtronic, model = "512/712", bolusSize = 0.1, @@ -219,14 +246,20 @@ enum class PumpType { baseBasalStep = 0.05, baseBasalSpecialSteps = null, pumpCapability = PumpCapability.MedtronicCapabilities, - source = Sources.Medtronic), - MEDTRONIC_515_715(description = "Medtronic 515/715", + source = Sources.Medtronic + ), + MEDTRONIC_515_715( + description = "Medtronic 515/715", model = "515/715", - parent = MEDTRONIC_512_712), - MEDTRONIC_522_722(description = "Medtronic 522/722", + parent = MEDTRONIC_512_712 + ), + MEDTRONIC_522_722( + description = "Medtronic 522/722", model = "522/722", - parent = MEDTRONIC_512_712), - MEDTRONIC_523_723_REVEL(description = "Medtronic 523/723 (Revel)", + parent = MEDTRONIC_512_712 + ), + MEDTRONIC_523_723_REVEL( + description = "Medtronic 523/723 (Revel)", manufacturer = ManufacturerType.Medtronic, model = "523/723 (Revel)", bolusSize = 0.05, @@ -239,9 +272,11 @@ enum class PumpType { baseBasalStep = 0.025, baseBasalSpecialSteps = DoseStepSize.MedtronicVeoBasal, pumpCapability = PumpCapability.MedtronicCapabilities, - source = Sources.Medtronic), + source = Sources.Medtronic + ), MEDTRONIC_554_754_VEO(description = "Medtronic 554/754 (Veo)", model = "554/754 (Veo)", parent = MEDTRONIC_523_723_REVEL), - MEDTRONIC_640G(description = "Medtronic 640G", + MEDTRONIC_640G( + description = "Medtronic 640G", manufacturer = ManufacturerType.Medtronic, model = "640G", bolusSize = 0.025, @@ -253,9 +288,11 @@ enum class PumpType { baseBasalMinValue = 0.025, baseBasalStep = 0.025, baseBasalSpecialSteps = DoseStepSize.MedtronicVeoBasal, - pumpCapability = PumpCapability.VirtualPumpCapabilities), + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), - TANDEM_T_SLIM(description = "Tandem t:slim", + TANDEM_T_SLIM( + description = "Tandem t:slim", manufacturer = ManufacturerType.Tandem, model = "t:slim", bolusSize = 0.01, @@ -267,12 +304,14 @@ enum class PumpType { baseBasalMinValue = 0.1, baseBasalStep = 0.001, baseBasalSpecialSteps = null, - pumpCapability = PumpCapability.VirtualPumpCapabilities), + pumpCapability = PumpCapability.VirtualPumpCapabilities + ), TANDEM_T_FLEX(description = "Tandem t:flex", model = "t:flex", parent = TANDEM_T_SLIM), TANDEM_T_SLIM_G4(description = "Tandem t:slim G4", model = "t:slim G4", parent = TANDEM_T_SLIM), TANDEM_T_SLIM_X2(description = "Tandem t:slim X2", model = "t:slim X2", parent = TANDEM_T_SLIM), - YPSOPUMP(description = "YpsoPump", + YPSOPUMP( + description = "YpsoPump", manufacturer = ManufacturerType.Ypsomed, model = "Ypsopump", bolusSize = 0.1, @@ -285,26 +324,39 @@ enum class PumpType { baseBasalMaxValue = 40.0, baseBasalStep = 0.01, baseBasalSpecialSteps = DoseStepSize.YpsopumpBasal, - pumpCapability = PumpCapability.YpsomedCapabilities), - MDI(description = "MDI", + pumpCapability = PumpCapability.YpsomedCapabilities + ), + MDI( + description = "MDI", manufacturer = ManufacturerType.AndroidAPS, bolusSize = 0.5, model = "MDI", tbrSettings = DoseSettings(1.0, 15, 24 * 60, 0.0, 500.0), extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), - pumpCapability = PumpCapability.MDI), + pumpCapability = PumpCapability.MDI + ), // Not real pump. Used for User as a source - USER(description = "USER", + USER( + description = "USER", manufacturer = ManufacturerType.AndroidAPS, model = "USER", tbrSettings = DoseSettings(1.0, 15, 24 * 60, 0.0, 500.0), extendedBolusSettings = DoseSettings(0.1, 15, 12 * 60, 0.1), pumpCapability = PumpCapability.MDI, - source = Sources.MDI), + source = Sources.MDI + ), + + // Not real, cached value + CACHE( + description = "CACHE", + model = "CACHE", + parent = USER + ), //Diaconn Pump - DIACONN_G8(description = "Diaconn G8", + DIACONN_G8( + description = "Diaconn G8", manufacturer = ManufacturerType.G2e, model = "DiaconnG8", bolusSize = 0.01, @@ -319,7 +371,8 @@ enum class PumpType { baseBasalSpecialSteps = null, pumpCapability = PumpCapability.DiaconnCapabilities, source = Sources.DiaconnG8, - useHardwareLink = true); + useHardwareLink = true + ); val description: String var manufacturer: ManufacturerType? = null @@ -407,6 +460,7 @@ enum class PumpType { InterfaceIDs.PumpType.MDI -> MDI InterfaceIDs.PumpType.USER -> USER InterfaceIDs.PumpType.DIACONN_G8 -> DIACONN_G8 + InterfaceIDs.PumpType.CACHE -> TODO() } } @@ -418,25 +472,27 @@ enum class PumpType { parent.model = model } - constructor(description: String, - manufacturer: ManufacturerType, - model: String, - bolusSize: Double = 0.0, - specialBolusSize: DoseStepSize? = null, - extendedBolusSettings: DoseSettings, - pumpTempBasalType: PumpTempBasalType? = null, - tbrSettings: DoseSettings, - specialBasalDurations: PumpCapability? = null, - baseBasalMinValue: Double = 0.01, - baseBasalMaxValue: Double? = null, - baseBasalStep: Double = 1.0, - baseBasalSpecialSteps: DoseStepSize? = null, - pumpCapability: PumpCapability, - hasCustomUnreachableAlertCheck: Boolean = false, - isPatchPump: Boolean = false, - supportBatteryLevel: Boolean = true, - useHardwareLink: Boolean = false, - source: Sources = Sources.VirtualPump) { + constructor( + description: String, + manufacturer: ManufacturerType, + model: String, + bolusSize: Double = 0.0, + specialBolusSize: DoseStepSize? = null, + extendedBolusSettings: DoseSettings, + pumpTempBasalType: PumpTempBasalType? = null, + tbrSettings: DoseSettings, + specialBasalDurations: PumpCapability? = null, + baseBasalMinValue: Double = 0.01, + baseBasalMaxValue: Double? = null, + baseBasalStep: Double = 1.0, + baseBasalSpecialSteps: DoseStepSize? = null, + pumpCapability: PumpCapability, + hasCustomUnreachableAlertCheck: Boolean = false, + isPatchPump: Boolean = false, + supportBatteryLevel: Boolean = true, + useHardwareLink: Boolean = false, + source: Sources = Sources.VirtualPump + ) { this.description = description this.manufacturer = manufacturer this.model = model @@ -463,12 +519,14 @@ enum class PumpType { val eb = extendedBolusSettings ?: return "INVALID" val tbr = tbrSettings ?: return "INVALID" val extendedNote = if (hasExtendedBasals) rh.gs(R.string.def_extended_note) else "" - return String.format(i18nTemplate, + return String.format( + i18nTemplate, getStep("" + bolusSize, specialBolusSize), eb.step, eb.durationStep, eb.maxDuration / 60, getStep(baseBasalRange(), baseBasalSpecialSteps), tbr.minDose.toString() + unit + "-" + tbr.maxDose + unit, tbr.step.toString() + unit, - tbr.durationStep, tbr.maxDuration / 60, extendedNote) + tbr.durationStep, tbr.maxDuration / 60, extendedNote + ) } private fun baseBasalRange(): String = @@ -494,42 +552,45 @@ enum class PumpType { fun determineCorrectBasalSize(basalAmount: Double): Double { val tSettings = tbrSettings ?: throw IllegalStateException() - return Round.roundTo(min(basalAmount, tSettings.maxDose), baseBasalSpecialSteps?.getStepSizeForAmount(basalAmount) - ?: baseBasalStep) + return Round.roundTo( + min(basalAmount, tSettings.maxDose), baseBasalSpecialSteps?.getStepSizeForAmount(basalAmount) + ?: baseBasalStep + ) } fun toDbPumpType(): InterfaceIDs.PumpType = when (this) { - GENERIC_AAPS -> InterfaceIDs.PumpType.GENERIC_AAPS - CELLNOVO -> InterfaceIDs.PumpType.CELLNOVO - ACCU_CHEK_COMBO -> InterfaceIDs.PumpType.ACCU_CHEK_COMBO - ACCU_CHEK_SPIRIT -> InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT + GENERIC_AAPS -> InterfaceIDs.PumpType.GENERIC_AAPS + CELLNOVO -> InterfaceIDs.PumpType.CELLNOVO + ACCU_CHEK_COMBO -> InterfaceIDs.PumpType.ACCU_CHEK_COMBO + ACCU_CHEK_SPIRIT -> InterfaceIDs.PumpType.ACCU_CHEK_SPIRIT ACCU_CHEK_INSIGHT_VIRTUAL -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT ACCU_CHEK_INSIGHT -> InterfaceIDs.PumpType.ACCU_CHEK_INSIGHT_BLUETOOTH ACCU_CHEK_SOLO -> InterfaceIDs.PumpType.ACCU_CHEK_SOLO - ANIMAS_VIBE -> InterfaceIDs.PumpType.ANIMAS_VIBE - ANIMAS_PING -> InterfaceIDs.PumpType.ANIMAS_PING - DANA_R -> InterfaceIDs.PumpType.DANA_R - DANA_R_KOREAN -> InterfaceIDs.PumpType.DANA_R_KOREAN - DANA_RS -> InterfaceIDs.PumpType.DANA_RS - DANA_RS_KOREAN -> InterfaceIDs.PumpType.DANA_RS_KOREAN - DANA_RV2 -> InterfaceIDs.PumpType.DANA_RV2 - DANA_I -> InterfaceIDs.PumpType.DANA_I - OMNIPOD_EROS -> InterfaceIDs.PumpType.OMNIPOD_EROS - OMNIPOD_DASH -> InterfaceIDs.PumpType.OMNIPOD_DASH - MEDTRONIC_512_712 -> InterfaceIDs.PumpType.MEDTRONIC_512_517 - MEDTRONIC_515_715 -> InterfaceIDs.PumpType.MEDTRONIC_515_715 - MEDTRONIC_522_722 -> InterfaceIDs.PumpType.MEDTRONIC_522_722 - MEDTRONIC_523_723_REVEL -> InterfaceIDs.PumpType.MEDTRONIC_523_723_REVEL - MEDTRONIC_554_754_VEO -> InterfaceIDs.PumpType.MEDTRONIC_554_754_VEO - MEDTRONIC_640G -> InterfaceIDs.PumpType.MEDTRONIC_640G - TANDEM_T_SLIM -> InterfaceIDs.PumpType.TANDEM_T_SLIM - TANDEM_T_SLIM_G4 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_G4 - TANDEM_T_FLEX -> InterfaceIDs.PumpType.TANDEM_T_FLEX - TANDEM_T_SLIM_X2 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_X2 - YPSOPUMP -> InterfaceIDs.PumpType.YPSOPUMP - MDI -> InterfaceIDs.PumpType.MDI - USER -> InterfaceIDs.PumpType.USER - DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8 + ANIMAS_VIBE -> InterfaceIDs.PumpType.ANIMAS_VIBE + ANIMAS_PING -> InterfaceIDs.PumpType.ANIMAS_PING + DANA_R -> InterfaceIDs.PumpType.DANA_R + DANA_R_KOREAN -> InterfaceIDs.PumpType.DANA_R_KOREAN + DANA_RS -> InterfaceIDs.PumpType.DANA_RS + DANA_RS_KOREAN -> InterfaceIDs.PumpType.DANA_RS_KOREAN + DANA_RV2 -> InterfaceIDs.PumpType.DANA_RV2 + DANA_I -> InterfaceIDs.PumpType.DANA_I + OMNIPOD_EROS -> InterfaceIDs.PumpType.OMNIPOD_EROS + OMNIPOD_DASH -> InterfaceIDs.PumpType.OMNIPOD_DASH + MEDTRONIC_512_712 -> InterfaceIDs.PumpType.MEDTRONIC_512_517 + MEDTRONIC_515_715 -> InterfaceIDs.PumpType.MEDTRONIC_515_715 + MEDTRONIC_522_722 -> InterfaceIDs.PumpType.MEDTRONIC_522_722 + MEDTRONIC_523_723_REVEL -> InterfaceIDs.PumpType.MEDTRONIC_523_723_REVEL + MEDTRONIC_554_754_VEO -> InterfaceIDs.PumpType.MEDTRONIC_554_754_VEO + MEDTRONIC_640G -> InterfaceIDs.PumpType.MEDTRONIC_640G + TANDEM_T_SLIM -> InterfaceIDs.PumpType.TANDEM_T_SLIM + TANDEM_T_SLIM_G4 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_G4 + TANDEM_T_FLEX -> InterfaceIDs.PumpType.TANDEM_T_FLEX + TANDEM_T_SLIM_X2 -> InterfaceIDs.PumpType.TANDEM_T_SLIM_X2 + YPSOPUMP -> InterfaceIDs.PumpType.YPSOPUMP + MDI -> InterfaceIDs.PumpType.MDI + USER -> InterfaceIDs.PumpType.USER + DIACONN_G8 -> InterfaceIDs.PumpType.DIACONN_G8 + CACHE -> InterfaceIDs.PumpType.CACHE } } diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index ad6be79def..2ce6796e66 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.database import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.database.data.NewEntries +import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.interfaces.DBEntry import info.nightscout.androidaps.database.transactions.Transaction @@ -59,6 +60,10 @@ import kotlin.math.roundToInt fun clearDatabases() = database.clearAllTables() + fun clearCachedData(from: Long) { + database.totalDailyDoseDao.deleteNewerThan(from, InterfaceIDs.PumpType.CACHE) + } + //BG READINGS -- only valid records fun compatGetBgReadingsDataFromTime(timestamp: Long, ascending: Boolean): Single> = database.glucoseValueDao.compatGetBgReadingsDataFromTime(timestamp) @@ -775,22 +780,26 @@ import kotlin.math.roundToInt fun getOldestExtendedBolusRecord(): ExtendedBolus? = database.extendedBolusDao.getOldestRecord() - // TotalDailyDose - fun getAllTotalDailyDoses(ascending: Boolean): Single> = - database.totalDailyDoseDao.getAllTotalDailyDoses() - .map { if (!ascending) it.reversed() else it } + fun getLastExtendedBolusIdWrapped(): Single> = + database.extendedBolusDao.getLastId() .subscribeOn(Schedulers.io()) + .toWrappedSingle() + // TotalDailyDose fun getLastTotalDailyDoses(count: Int, ascending: Boolean): Single> = database.totalDailyDoseDao.getLastTotalDailyDoses(count) .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) - fun getLastExtendedBolusIdWrapped(): Single> = - database.extendedBolusDao.getLastId() + fun getCalculatedTotalDailyDose(timestamp: Long): Single> = + database.totalDailyDoseDao.findByTimestamp(timestamp, InterfaceIDs.PumpType.CACHE) .subscribeOn(Schedulers.io()) .toWrappedSingle() + fun createTotalDailyDose(tdd: TotalDailyDose) { + database.totalDailyDoseDao.insert(tdd) + } + // OFFLINE EVENT /* * returns a Pair of the next entity to sync and the ID of the "update". diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt index d14d8b9bc0..5cb71c265a 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt @@ -2,11 +2,10 @@ package info.nightscout.androidaps.database.daos import androidx.room.Dao import androidx.room.Query -import info.nightscout.androidaps.database.TABLE_TEMPORARY_TARGETS import info.nightscout.androidaps.database.TABLE_TOTAL_DAILY_DOSES import info.nightscout.androidaps.database.embedments.InterfaceIDs -import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TotalDailyDose +import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.core.Single @Suppress("FunctionName") @@ -25,13 +24,16 @@ internal interface TotalDailyDoseDao : TraceableDao { @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE timestamp = :timestamp AND pumpType = :pumpType AND pumpSerial = :pumpSerial AND referenceId IS NULL") fun findByPumpTimestamp(timestamp: Long, pumpType: InterfaceIDs.PumpType, pumpSerial: String): TotalDailyDose? - @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") - fun getAllTotalDailyDoses(): Single> + @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE timestamp = :timestamp AND pumpType = :pumpType AND referenceId IS NULL") + fun findByTimestamp(timestamp: Long, pumpType: InterfaceIDs.PumpType): Maybe - @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp DESC LIMIT :count") - fun getLastTotalDailyDoses(count: Int): Single> + @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE isValid = 1 AND referenceId IS NULL AND pumpType <> :exclude ORDER BY timestamp DESC LIMIT :count") + fun getLastTotalDailyDoses(count: Int, exclude: InterfaceIDs.PumpType = InterfaceIDs.PumpType.CACHE): Single> @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE dateCreated > :since AND dateCreated <= :until LIMIT :limit OFFSET :offset") suspend fun getNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int): List + @Query("DELETE FROM $TABLE_TOTAL_DAILY_DOSES WHERE dateCreated >= :since AND pumpType = :pumpType") + fun deleteNewerThan(since: Long, pumpType: InterfaceIDs.PumpType) + } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt index 0477dc1c8d..7306c89d1f 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt @@ -42,7 +42,8 @@ data class InterfaceIDs( YPSOPUMP, MDI, DIACONN_G8, - USER; + USER, + CACHE; companion object {