IobCobCalculator refactor

This commit is contained in:
Milos Kozak 2021-04-12 19:49:12 +02:00
parent 639328bdc3
commit c637b7072c
30 changed files with 222 additions and 221 deletions

View file

@ -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(),

View file

@ -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

View file

@ -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

View file

@ -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(),

View file

@ -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) {

View file

@ -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<DataPointWithLabelInterface> = 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<DataPointWithLabelInterface> = ArrayList()

View file

@ -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 },

View file

@ -78,9 +78,9 @@ open class IobCobCalculatorPlugin @Inject constructor(
private var absIobTable = LongSparseArray<IobTotal>() // oldest at index 0, absolute insulin in the body
private var autosensDataTable = LongSparseArray<AutosensData>() // oldest at index 0
private var basalDataTable = LongSparseArray<BasalData>() // oldest at index 0
override var bgReadings: List<GlucoseValue> = listOf() // newest at index 0
internal var bgReadings: List<GlucoseValue> = listOf() // newest at index 0
@Volatile override var bucketedData: MutableList<InMemoryGlucoseValue>? = null
internal var bucketedData: MutableList<InMemoryGlucoseValue>? = 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<AutosensData> {
return autosensDataTable
}
override fun getBgReadingsDataTableCopy(): List<GlucoseValue> = bgReadings.toList()
override fun getBucketedDataTableCopy(): MutableList<InMemoryGlucoseValue>? = bucketedData?.toMutableList()
override fun getAutosensDataTable(): LongSparseArray<AutosensData> = 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<IobTotal> {
// 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")

View file

@ -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)

View file

@ -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)

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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<GlucoseValue> = 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)

View file

@ -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)
}

View file

@ -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()))

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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

View file

@ -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())

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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) {

View file

@ -17,25 +17,28 @@ import org.json.JSONArray
interface IobCobCalculator {
val dataLock: Any
var bgReadings: List<GlucoseValue>
var bucketedData: MutableList<InMemoryGlucoseValue>?
val mealData: MealData
fun getBgReadingsDataTableCopy(): List<GlucoseValue>
fun getBucketedDataTableCopy(): MutableList<InMemoryGlucoseValue>?
fun getAutosensDataTable(): LongSparseArray<AutosensData>
fun calculateIobArrayInDia(profile: Profile): Array<IobTotal>
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<IobTotal>
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<IobTotal>
fun iobArrayToString(array: Array<IobTotal>): String
fun slowAbsorptionPercentage(timeInMinutes: Int): Double
fun convertToJSONArray(iobArray: Array<IobTotal>): 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

View file

@ -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<Double>()
val lastDeltas = ArrayList<Double>()
val shortDeltas = ArrayList<Double>()
val longDeltas = ArrayList<Double>()
// 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<Double>()
val lastDeltas = ArrayList<Double>()
val shortDeltas = ArrayList<Double>()
val longDeltas = ArrayList<Double>()
// 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 {

View file

@ -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}]