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.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository 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.TemporaryTarget
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources 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.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogCarbsBinding import info.nightscout.androidaps.databinding.DialogCarbsBinding
import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
@ -49,7 +49,7 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var carbTimer: CarbTimer @Inject lateinit var carbTimer: CarbTimer
@Inject lateinit var commandQueue: CommandQueue @Inject lateinit var commandQueue: CommandQueue
@ -144,7 +144,7 @@ class CarbsDialog : DialogFragmentWithDate() {
validateInputs() validateInputs()
} }
iobCobCalculatorPlugin.actualBg()?.let { bgReading -> iobCobCalculator.actualBg()?.let { bgReading ->
if (bgReading.value < 72) if (bgReading.value < 72)
binding.hypoTt.isChecked = true binding.hypoTt.isChecked = true
} }
@ -226,7 +226,7 @@ class CarbsDialog : DialogFragmentWithDate() {
activitySelected -> { activitySelected -> {
uel.log(Action.TT, Sources.CarbDialog, uel.log(Action.TT, Sources.CarbDialog,
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY), ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.ACTIVITY),
ValueWithUnit.fromGlucoseUnit(activityTT, units) , ValueWithUnit.fromGlucoseUnit(activityTT, units),
ValueWithUnit.Minute(activityTTDuration)) ValueWithUnit.Minute(activityTTDuration))
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
@ -245,7 +245,7 @@ class CarbsDialog : DialogFragmentWithDate() {
eatingSoonSelected -> { eatingSoonSelected -> {
uel.log(Action.TT, Sources.CarbDialog, uel.log(Action.TT, Sources.CarbDialog,
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON), ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.EATING_SOON),
ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units) , ValueWithUnit.fromGlucoseUnit(eatingSoonTT, units),
ValueWithUnit.Minute(eatingSoonTTDuration)) ValueWithUnit.Minute(eatingSoonTTDuration))
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), timestamp = System.currentTimeMillis(),
@ -264,7 +264,7 @@ class CarbsDialog : DialogFragmentWithDate() {
hypoSelected -> { hypoSelected -> {
uel.log(Action.TT, Sources.CarbDialog, uel.log(Action.TT, Sources.CarbDialog,
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA), ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.HYPOGLYCEMIA),
ValueWithUnit.fromGlucoseUnit(hypoTT, units) , ValueWithUnit.fromGlucoseUnit(hypoTT, units),
ValueWithUnit.Minute(hypoTTDuration)) ValueWithUnit.Minute(hypoTTDuration))
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction( disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(), 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.IobTotal
import info.nightscout.androidaps.data.MealData import info.nightscout.androidaps.data.MealData
import info.nightscout.androidaps.data.Profile 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.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger 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.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus 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 info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException

View file

@ -107,7 +107,7 @@ open class OpenAPSAMAPlugin @Inject constructor(
val iobArray = iobCobCalculator.calculateIobArrayInDia(profile) val iobArray = iobCobCalculator.calculateIobArrayInDia(profile)
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart) profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
val mealData = iobCobCalculator.mealData val mealData = iobCobCalculator.getMealDataWithWaitingForCalculationFinish()
profiler.log(LTag.APS, "getMealData()", startPart) profiler.log(LTag.APS, "getMealData()", startPart)
val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint -> val maxIob = constraintChecker.getMaxIOBAllowed().also { maxIOBAllowedConstraint ->
inputConstraints.copyReasons(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 if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
if (constraintChecker.isAutosensModeEnabled().value()) { if (constraintChecker.isAutosensModeEnabled().value()) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
if (autosensData == null) { if (autosensData == null) {
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
return 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 if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
startPart = System.currentTimeMillis() startPart = System.currentTimeMillis()
if (constraintChecker.isAutosensModeEnabled().value()) { if (constraintChecker.isAutosensModeEnabled().value()) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("OpenAPSPlugin") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
if (autosensData == null) { if (autosensData == null) {
rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata))) rxBus.send(EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openaps_noasdata)))
return return
@ -169,7 +169,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
activePlugin.activePump.baseBasalRate, activePlugin.activePump.baseBasalRate,
iobArray, iobArray,
glucoseStatus, glucoseStatus,
iobCobCalculator.mealData, iobCobCalculator.getMealDataWithWaitingForCalculationFinish(),
lastAutosensResult.ratio, lastAutosensResult.ratio,
isTempTarget, isTempTarget,
smbAllowed.value(), smbAllowed.value(),

View file

@ -3,11 +3,11 @@ package info.nightscout.androidaps.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin 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.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import javax.inject.Inject import javax.inject.Inject
@ -19,7 +19,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
init { init {
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) { 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) { tasks.add(object : Task(this, R.string.hasbgdata) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return iobCobCalculatorPlugin.lastBg() != null return iobCobCalculator.lastBg() != null
} }
}) })
tasks.add(object : Task(this, R.string.loopenabled) { tasks.add(object : Task(this, R.string.loopenabled) {

View file

@ -62,7 +62,7 @@ class GraphData(
} }
fun addBucketedData(fromTime: Long, toTime: Long) { fun addBucketedData(fromTime: Long, toTime: Long) {
val bucketedData = iobCobCalculator.bucketedData ?: return val bucketedData = iobCobCalculator.getBucketedDataTableCopy() ?: return
if (bucketedData.isEmpty()) { if (bucketedData.isEmpty()) {
aapsLogger.debug("No bucketed data.") aapsLogger.debug("No bucketed data.")
return return
@ -70,7 +70,7 @@ class GraphData(
val bucketedListArray: MutableList<DataPointWithLabelInterface> = ArrayList() val bucketedListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
for (inMemoryGlucoseValue in bucketedData) { for (inMemoryGlucoseValue in bucketedData) {
if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue 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] })) addSeries(PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }))
} }
@ -426,7 +426,7 @@ class GraphData(
it.thickness = 3 it.thickness = 3
} }
if (showPrediction) { if (showPrediction) {
val autosensData = iobCobCalculator.getLastAutosensDataSynchronized("GraphData") val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData")
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult() val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList() 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.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.TDD import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction 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.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -71,7 +70,7 @@ class ActionStringHandler @Inject constructor(
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val commandQueue: CommandQueueProvider, private val commandQueue: CommandQueueProvider,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculator: IobCobCalculator,
private val localInsightPlugin: LocalInsightPlugin, private val localInsightPlugin: LocalInsightPlugin,
private val danaRPlugin: DanaRPlugin, private val danaRPlugin: DanaRPlugin,
private val danaRKoreanPlugin: DanaRKoreanPlugin, private val danaRKoreanPlugin: DanaRKoreanPlugin,
@ -104,7 +103,7 @@ class ActionStringHandler @Inject constructor(
.subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException) .subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException)
} }
fun tearDown(){ fun tearDown() {
disposable.clear() disposable.clear()
} }
@ -208,12 +207,12 @@ class ActionStringHandler @Inject constructor(
sendError("No profile found!") sendError("No profile found!")
return return
} }
val bgReading = iobCobCalculatorPlugin.actualBg() val bgReading = iobCobCalculator.actualBg()
if (bgReading == null) { if (bgReading == null) {
sendError("No recent BG to base calculation on!") sendError("No recent BG to base calculation on!")
return return
} }
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Wizard wear") val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
if (cobInfo.displayCob == null) { if (cobInfo.displayCob == null) {
sendError("Unknown COB! BG reading missing or recent app restart?") sendError("Unknown COB! BG reading missing or recent app restart?")
return return
@ -624,10 +623,10 @@ class ActionStringHandler @Inject constructor(
} }
private fun doECarbs(carbs: Int, time: Long, duration: Int) { 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.Timestamp(time),
ValueWithUnit.Gram(carbs), ValueWithUnit.Gram(carbs),
ValueWithUnit.Hour(duration).takeIf { duration !=0 }) ValueWithUnit.Hour(duration).takeIf { duration != 0 })
doBolus(0.0, carbs, time, duration) doBolus(0.0, carbs, time, duration)
} }
@ -640,10 +639,10 @@ class ActionStringHandler @Inject constructor(
detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs() detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs()
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
val action = when { val action = when {
amount.equals(0.0) -> Action.CARBS amount.equals(0.0) -> Action.CARBS
carbs.equals(0) -> Action.BOLUS carbs.equals(0) -> Action.BOLUS
carbsDuration>0 -> Action.EXTENDED_CARBS carbsDuration > 0 -> Action.EXTENDED_CARBS
else -> Action.TREATMENT else -> Action.TREATMENT
} }
uel.log(action, Sources.Wear, uel.log(action, Sources.Wear,
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 }, 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 absIobTable = LongSparseArray<IobTotal>() // oldest at index 0, absolute insulin in the body
private var autosensDataTable = LongSparseArray<AutosensData>() // oldest at index 0 private var autosensDataTable = LongSparseArray<AutosensData>() // oldest at index 0
private var basalDataTable = LongSparseArray<BasalData>() // 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 // 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 // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
@ -135,9 +135,9 @@ open class IobCobCalculatorPlugin @Inject constructor(
super.onStop() super.onStop()
} }
override fun getAutosensDataTable(): LongSparseArray<AutosensData> { override fun getBgReadingsDataTableCopy(): List<GlucoseValue> = bgReadings.toList()
return autosensDataTable override fun getBucketedDataTableCopy(): MutableList<InMemoryGlucoseValue>? = bucketedData?.toMutableList()
} override fun getAutosensDataTable(): LongSparseArray<AutosensData> = autosensDataTable
private fun adjustToReferenceTime(someTime: Long): Long { private fun adjustToReferenceTime(someTime: Long): Long {
if (referenceTime == -1L) { 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) { if (thread?.isAlive == true) {
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason") aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA is waiting for calculation thread: $reason")
try { try {
@ -515,8 +515,10 @@ open class IobCobCalculatorPlugin @Inject constructor(
synchronized(dataLock) { return getLastAutosensData(reason) } synchronized(dataLock) { return getLastAutosensData(reason) }
} }
override fun getCobInfo(_synchronized: Boolean, reason: String): CobInfo { override fun getCobInfo(waitForCalculationFinish: Boolean, reason: String): CobInfo {
val autosensData = if (_synchronized) getLastAutosensDataSynchronized(reason) else getLastAutosensData(reason) val autosensData =
if (waitForCalculationFinish) getLastAutosensDataWithWaitForCalculationFinish(reason)
else getLastAutosensData(reason)
var displayCob: Double? = null var displayCob: Double? = null
var futureCarbs = 0.0 var futureCarbs = 0.0
val now = dateUtil.now() val now = dateUtil.now()
@ -576,39 +578,38 @@ open class IobCobCalculatorPlugin @Inject constructor(
} }
} }
override fun lastDataTime(): String { override fun lastDataTime(): String =
return if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time) else "autosensDataTable empty" if (autosensDataTable.size() > 0) dateUtil.dateAndTimeAndSecondsString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time)
} else "autosensDataTable empty"
override val mealData: MealData override fun getMealDataWithWaitingForCalculationFinish(): MealData {
get() { val result = MealData()
val result = MealData() val now = System.currentTimeMillis()
val now = System.currentTimeMillis() val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) {
val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) { sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME) } else {
} else { sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
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
} }
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> { override fun calculateIobArrayInDia(profile: Profile): Array<IobTotal> {
// predict IOB out to DIA plus 30m // predict IOB out to DIA plus 30m
@ -656,7 +657,7 @@ open class IobCobCalculatorPlugin @Inject constructor(
if (thread?.state != Thread.State.TERMINATED) { if (thread?.state != Thread.State.TERMINATED) {
stopCalculationTrigger = true stopCalculationTrigger = true
aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from") 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) SystemClock.sleep(100)
} }
aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from") aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from")

View file

@ -81,7 +81,7 @@ class IobCobOref1Thread internal constructor(
iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.loadBgData(end)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
} }
val bucketedData = iobCobCalculatorPlugin.bucketedData val bucketedData = iobCobCalculatorPlugin.getBucketedDataTableCopy()
val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable()
if (bucketedData == null || bucketedData.size < 3) { if (bucketedData == null || bucketedData.size < 3) {
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
@ -156,7 +156,7 @@ class IobCobOref1Thread internal constructor(
if (ad == null) { if (ad == null) {
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
aapsLogger.debug(LTag.AUTOSENS, bucketedData.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) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -179,7 +179,7 @@ class IobCobOref1Thread internal constructor(
fabricPrivacy.logException(e) fabricPrivacy.logException(e)
aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(autosensDataTable.toString())
aapsLogger.debug(bucketedData.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) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)

View file

@ -79,7 +79,7 @@ class IobCobThread @Inject internal constructor(
iobCobCalculatorPlugin.loadBgData(end) iobCobCalculatorPlugin.loadBgData(end)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
} }
val bucketedData = iobCobCalculatorPlugin.bucketedData val bucketedData = iobCobCalculatorPlugin.getBucketedDataTableCopy()
val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable() val autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable()
if (bucketedData == null || bucketedData.size < 3) { if (bucketedData == null || bucketedData.size < 3) {
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from") aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
@ -152,7 +152,7 @@ class IobCobThread @Inject internal constructor(
if (ad == null) { if (ad == null) {
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
aapsLogger.debug(LTag.AUTOSENS, bucketedData.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) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)
@ -175,7 +175,7 @@ class IobCobThread @Inject internal constructor(
fabricPrivacy.logException(e) fabricPrivacy.logException(e)
aapsLogger.debug(autosensDataTable.toString()) aapsLogger.debug(autosensDataTable.toString())
aapsLogger.debug(bucketedData.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) val notification = Notification(Notification.SEND_LOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW)
rxBus.send(EventNewNotification(notification)) rxBus.send(EventNewNotification(notification))
sp.putBoolean("log_AUTOSENS", true) sp.putBoolean("log_AUTOSENS", true)

View file

@ -31,10 +31,10 @@ import kotlin.math.roundToInt
@Singleton @Singleton
open class SensitivityOref1Plugin @Inject constructor( open class SensitivityOref1Plugin @Inject constructor(
injector: HasAndroidInjector?, injector: HasAndroidInjector,
aapsLogger: AAPSLogger?, aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper?, resourceHelper: ResourceHelper,
sp: SP?, sp: SP,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface, private val databaseHelper: DatabaseHelperInterface,
@ -48,7 +48,7 @@ open class SensitivityOref1Plugin @Inject constructor(
.preferencesId(R.xml.pref_absorption_oref1) .preferencesId(R.xml.pref_absorption_oref1)
.description(R.string.description_sensitivity_oref1) .description(R.string.description_sensitivity_oref1)
.setDefault(), .setDefault(),
injector!!, aapsLogger!!, resourceHelper!!, sp!! injector, aapsLogger, resourceHelper, sp
) { ) {
override fun detectSensitivity(plugin: IobCobCalculator, fromTime: Long, toTime: Long): AutosensResult { 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.Config
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventProfileNeedsUpdate import info.nightscout.androidaps.events.EventProfileNeedsUpdate
import info.nightscout.androidaps.extensions.buildDeviceStatus
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration 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.queue.commands.Command
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.LocalAlertUtils import info.nightscout.androidaps.utils.LocalAlertUtils
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.extensions.buildDeviceStatus
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
@ -61,7 +61,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
@Inject lateinit var localAlertUtils: LocalAlertUtils @Inject lateinit var localAlertUtils: LocalAlertUtils
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var loopPlugin: LoopPlugin @Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@ -102,12 +102,12 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
var shouldUploadStatus = false var shouldUploadStatus = false
if (config.NSCLIENT) return if (config.NSCLIENT) return
if (config.PUMPCONTROL) shouldUploadStatus = true if (config.PUMPCONTROL) shouldUploadStatus = true
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null) else if (!loopPlugin.isEnabled() || iobCobCalculator.actualBg() == null)
shouldUploadStatus = true shouldUploadStatus = true
else if (dateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true else if (dateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
if (dateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) { if (dateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) {
lastIobUpload = dateUtil.now() lastIobUpload = dateUtil.now()
buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculatorPlugin, profileFunction, buildDeviceStatus(dateUtil, loopPlugin, iobCobCalculator, profileFunction,
activePlugin.activePump, receiverStatusStore, runningConfiguration, activePlugin.activePump, receiverStatusStore, runningConfiguration,
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also { BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
repository.insert(it) 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.AppRepository
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag 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.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -34,7 +34,7 @@ class LocalAlertUtils @Inject constructor(
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculator: IobCobCalculator,
private val smsCommunicatorPlugin: SmsCommunicatorPlugin, private val smsCommunicatorPlugin: SmsCommunicatorPlugin,
private val config: Config, private val config: Config,
private val repository: AppRepository, private val repository: AppRepository,
@ -110,7 +110,7 @@ class LocalAlertUtils @Inject constructor(
} }
fun checkStaleBGAlert() { fun checkStaleBGAlert() {
val bgReading = iobCobCalculatorPlugin.lastBg() val bgReading = iobCobCalculator.lastBg()
if (sp.getBoolean(R.string.key_enable_missed_bg_readings_alert, false) 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()) { && 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) 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.maintenance.LoggerUtils
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider 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.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage import info.nightscout.androidaps.plugins.pump.common.bolusInfo.TemporaryBasalStorage
@ -54,7 +53,7 @@ import java.util.*
ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class,
OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class,
VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, TemporaryBasalStorage::class, GlimpPlugin::class, Profiler::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() { class ConstraintsCheckerTest : TestBaseWithProfile() {
@Mock lateinit var activePlugin: ActivePluginProvider @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.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction 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.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker 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.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider 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.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
@ -55,7 +58,7 @@ import java.util.*
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class,
SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::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) AppRepository::class, DateUtil::class)
class SmsCommunicatorPluginTest : TestBaseWithProfile() { class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@ -96,8 +99,6 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
val bgList: MutableList<GlucoseValue> = ArrayList() val bgList: MutableList<GlucoseValue> = ArrayList()
bgList.add(reading) 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.getCobInfo(false, "SMS COB")).thenReturn(CobInfo(10.0, 2.0))
`when`(iobCobCalculator.lastBg()).thenReturn(reading) `when`(iobCobCalculator.lastBg()).thenReturn(reading)

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.iob.iobCobCalculator package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import android.content.Context import android.content.Context
import android.os.PowerManager
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
@ -22,6 +23,7 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
import java.util.* import java.util.*
@ -41,18 +43,25 @@ class IobCobCalculatorPluginTest : TestBase() {
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var powerManager: PowerManager
lateinit var dateUtil: DateUtil lateinit var dateUtil: DateUtil
lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin private lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
val injector = HasAndroidInjector { val injector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is IobCobThread) {
it.context = context
it.resourceHelper = resourceHelper
}
} }
} }
@Before @Before
fun mock() { fun mock() {
dateUtil = DateUtil(context) 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) 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.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider 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.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
@ -28,7 +27,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, IobCobCalculatorPlugin::class, DateUtil::class) @PrepareForTest(ConstraintChecker::class, VirtualPumpPlugin::class, DateUtil::class)
class BolusWizardTest : TestBase() { class BolusWizardTest : TestBase() {
private val pumpBolusStep = 0.1 private val pumpBolusStep = 0.1
@ -71,7 +70,6 @@ class BolusWizardTest : TestBase() {
`when`(profile.ic).thenReturn(insulinToCarbRatio) `when`(profile.ic).thenReturn(insulinToCarbRatio)
`when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL)
`when`(iobCobCalculator.dataLock).thenReturn(Any())
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin) `when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis())) `when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis()))
`when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).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 locationDataContainer: LastLocationDataContainer
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil

View file

@ -30,7 +30,7 @@ class TriggerAutosensValue(injector: HasAndroidInjector) : Trigger(injector) {
} }
override fun shouldRun(): Boolean { 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) { ?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true true

View file

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

View file

@ -34,7 +34,7 @@ class TriggerIob(injector: HasAndroidInjector) : Trigger(injector) {
override fun shouldRun(): Boolean { override fun shouldRun(): Boolean {
val profile = profileFunction.getProfile() ?: return false 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)) { if (comparator.value.check(iob.iob, insulin.value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true return true

View file

@ -25,7 +25,7 @@ class TriggerAutosensValueTest : TriggerTestBase() {
@Test fun shouldRunTest() { @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_max), ArgumentMatchers.anyDouble())).thenReturn(1.2)
`when`(sp.getDouble(Mockito.eq(R.string.key_openapsama_autosens_min), ArgumentMatchers.anyDouble())).thenReturn(0.7) `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) var t = TriggerAutosensValue(injector)
t.autosens.value = 110.0 t.autosens.value = 110.0
t.comparator.value = Comparator.Compare.IS_EQUAL t.comparator.value = Comparator.Compare.IS_EQUAL
@ -65,14 +65,14 @@ class TriggerAutosensValueTest : TriggerTestBase() {
t.autosens.value = 390.0 t.autosens.value = 390.0
t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER
Assert.assertTrue(t.shouldRun()) 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 = TriggerAutosensValue(injector)
t.autosens.value = 80.0 t.autosens.value = 80.0
t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER t.comparator.value = Comparator.Compare.IS_EQUAL_OR_LESSER
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
// Test autosensData == null and Comparator == IS_NOT_AVAILABLE // 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 = TriggerAutosensValue(injector)
t.comparator.value = Comparator.Compare.IS_NOT_AVAILABLE t.comparator.value = Comparator.Compare.IS_NOT_AVAILABLE
Assert.assertTrue(t.shouldRun()) Assert.assertTrue(t.shouldRun())

View file

@ -26,13 +26,12 @@ class TriggerBgTest : TriggerTestBase() {
@Before @Before
fun prepare() { fun prepare() {
`when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL)
`when`(iobCobCalculatorPlugin.dataLock).thenReturn(Any())
`when`(dateUtil.now()).thenReturn(now) `when`(dateUtil.now()).thenReturn(now)
} }
@Test @Test
fun shouldRunTest() { 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) var t: TriggerBg = TriggerBg(injector).setUnits(Constants.MMOL).setValue(4.1).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(214.0).comparator(Comparator.Compare.IS_EQUAL) 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()) Assert.assertTrue(t.shouldRun())
t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER)
Assert.assertFalse(t.shouldRun()) 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) t = TriggerBg(injector).setUnits(Constants.MGDL).setValue(213.0).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerBg(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) t = TriggerBg(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE)

View file

@ -28,7 +28,7 @@ class TriggerCOBTest : TriggerTestBase() {
@Test fun shouldRunTest() { @Test fun shouldRunTest() {
// COB value is 6 // 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) var t: TriggerCOB = TriggerCOB(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL) t = TriggerCOB(injector).setValue(6.0).comparator(Comparator.Compare.IS_EQUAL)

View file

@ -20,7 +20,7 @@ import org.powermock.modules.junit4.PowerMockRunner
import java.util.* import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest(DateUtil::class, ProfileFunction::class) @PrepareForTest(DateUtil::class, ProfileFunction::class)
class TriggerDeltaTest : TriggerTestBase() { class TriggerDeltaTest : TriggerTestBase() {
var now = 1514766900000L var now = 1514766900000L
@ -28,12 +28,11 @@ class TriggerDeltaTest : TriggerTestBase() {
@Before @Before
fun mock() { fun mock() {
PowerMockito.`when`(dateUtil.now()).thenReturn(now) PowerMockito.`when`(dateUtil.now()).thenReturn(now)
`when`(iobCobCalculatorPlugin.dataLock).thenReturn(Any())
`when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL)
} }
@Test fun shouldRunTest() { @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) var t = TriggerDelta(injector).units(Constants.MGDL).setValue(73.0, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
Assert.assertEquals(DeltaType.LONG_AVERAGE, t.delta.deltaType) Assert.assertEquals(DeltaType.LONG_AVERAGE, t.delta.deltaType)
@ -55,7 +54,7 @@ class TriggerDeltaTest : TriggerTestBase() {
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerDelta(injector).units(Constants.MGDL).setValue(-0.2, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) t = TriggerDelta(injector).units(Constants.MGDL).setValue(-0.2, DeltaType.LONG_AVERAGE).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER)
Assert.assertTrue(t.shouldRun()) 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) t = TriggerDelta(injector).units(Constants.MGDL).setValue(213.0, DeltaType.DELTA).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerDelta(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) t = TriggerDelta(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE)

View file

@ -27,7 +27,7 @@ class TriggerIobTest : TriggerTestBase() {
} }
@Test fun shouldRunTest() { @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) var t: TriggerIob = TriggerIob(injector).setValue(1.1).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertFalse(t.shouldRun()) Assert.assertFalse(t.shouldRun())
t = TriggerIob(injector).setValue(1.0).comparator(Comparator.Compare.IS_EQUAL) 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 dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.TestPumpPlugin import info.nightscout.androidaps.TestPumpPlugin
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.PluginDescription 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.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.services.LastLocationDataContainer import info.nightscout.androidaps.services.LastLocationDataContainer
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.junit.Before import org.junit.Before
import org.mockito.Mock import org.mockito.Mock
@ -27,7 +25,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var locationDataContainer: LastLocationDataContainer @Mock lateinit var locationDataContainer: LastLocationDataContainer
@Mock lateinit var activePlugin: ActivePluginProvider @Mock lateinit var activePlugin: ActivePluginProvider
@Mock lateinit var iobCobCalculatorPlugin: IobCobCalculator @Mock lateinit var iobCobCalculator: IobCobCalculator
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var automationPlugin: AutomationPlugin @Mock lateinit var automationPlugin: AutomationPlugin
@ -53,8 +51,8 @@ open class TriggerTestBase : TestBaseWithProfile() {
it.locationDataContainer = locationDataContainer it.locationDataContainer = locationDataContainer
it.repository = repository it.repository = repository
it.activePlugin = activePlugin it.activePlugin = activePlugin
it.iobCobCalculatorPlugin = iobCobCalculatorPlugin it.iobCobCalculator = iobCobCalculator
it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil) it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculator, dateUtil)
it.dateUtil = dateUtil it.dateUtil = dateUtil
} }
if (it is TriggerBg) { if (it is TriggerBg) {

View file

@ -17,25 +17,28 @@ import org.json.JSONArray
interface IobCobCalculator { interface IobCobCalculator {
val dataLock: Any 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 getAutosensDataTable(): LongSparseArray<AutosensData>
fun calculateIobArrayInDia(profile: Profile): Array<IobTotal>
fun getMealDataWithWaitingForCalculationFinish(): MealData
fun lastDataTime(): String fun lastDataTime(): String
fun getAutosensData(fromTime: Long): AutosensData? fun getAutosensData(fromTime: Long): AutosensData?
fun getLastAutosensData(reason: String): 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 calculateAbsInsulinFromTreatmentsAndTempsSynchronized(fromTime: Long): IobTotal
fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile): IobTotal fun calculateFromTreatmentsAndTempsSynchronized(time: Long, profile: Profile): IobTotal
fun getBasalData(profile: Profile, fromTime: Long): BasalData fun getBasalData(profile: Profile, fromTime: Long): BasalData
fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array<IobTotal> fun calculateIobArrayForSMB(lastAutosensResult: AutosensResult, exercise_mode: Boolean, half_basal_exercise_target: Int, isTempTarget: Boolean): Array<IobTotal>
fun iobArrayToString(array: Array<IobTotal>): String fun iobArrayToString(array: Array<IobTotal>): String
fun slowAbsorptionPercentage(timeInMinutes: Int): Double fun slowAbsorptionPercentage(timeInMinutes: Int): Double
fun convertToJSONArray(iobArray: Array<IobTotal>): JSONArray fun convertToJSONArray(iobArray: Array<IobTotal>): JSONArray
/** /**
* Return last valid (>39) GlucoseValue from database or null if db is empty * Return last valid (>39) GlucoseValue from database or null if db is empty
* *
@ -46,11 +49,11 @@ interface IobCobCalculator {
/** /**
* Calculate CobInfo to now() * 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 * @param reason caller identification
* @return CobInfo * @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 * 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 !!! * Running basal is added to the IOB !!!
* *
* @param timestamp * @param toTime
* @return IobTotal * @return IobTotal
*/ */
fun calculateAbsoluteIobTempBasals(toTime: Long): 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 * 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 * @return IobTotal
*/ */
fun calculateIobToTimeFromTempBasalsIncludingConvertedExtended(toTime: Long): IobTotal fun calculateIobToTimeFromTempBasalsIncludingConvertedExtended(toTime: Long): IobTotal

View file

@ -20,86 +20,84 @@ class GlucoseStatusProvider @Inject constructor(
get() = getGlucoseStatusData() get() = getGlucoseStatusData()
fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus? { fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus? {
synchronized(iobCobCalculator.dataLock) { val data = iobCobCalculator.getBgReadingsDataTableCopy()
val data = iobCobCalculator.bgReadings val sizeRecords = data.size
val sizeRecords = data.size if (sizeRecords == 0) {
if (sizeRecords == 0) { aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0")
aapsLogger.debug(LTag.GLUCOSE, "sizeRecords==0") return null
return null }
} if (data[0].timestamp < dateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
if (data[0].timestamp < dateUtil.now() - 7 * 60 * 1000L && !allowOldData) { aapsLogger.debug(LTag.GLUCOSE, "oldData")
aapsLogger.debug(LTag.GLUCOSE, "oldData") return null
return null }
} val now = data[0]
val now = data[0] val nowDate = now.timestamp
val nowDate = now.timestamp var change: Double
var change: Double if (sizeRecords == 1) {
if (sizeRecords == 1) { aapsLogger.debug(LTag.GLUCOSE, "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)
}
return GlucoseStatus( return GlucoseStatus(
glucose = now.value, glucose = now.value,
date = nowDate, noise = 0.0,
noise = 0.0, //for now set to nothing as not all CGMs report noise delta = 0.0,
shortAvgDelta = shortAverageDelta, shortAvgDelta = 0.0,
delta = delta, longAvgDelta = 0.0,
longAvgDelta = average(longDeltas), date = nowDate
).also { aapsLogger.debug(LTag.GLUCOSE, it.log()) }.asRounded() ).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 { companion object {

View file

@ -13,7 +13,6 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
@ -41,7 +40,7 @@ class GlucoseStatusTest : TestBase() {
} }
@Test fun calculateValidGlucoseStatus() { @Test fun calculateValidGlucoseStatus() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateValidBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData())
val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001)
Assert.assertEquals(-2.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-2.0, glucoseStatus.delta, 0.001)
@ -51,7 +50,7 @@ class GlucoseStatusTest : TestBase() {
} }
@Test fun calculateMostRecentGlucoseStatus() { @Test fun calculateMostRecentGlucoseStatus() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateMostRecentBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateMostRecentBgData())
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
Assert.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2 Assert.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2
Assert.assertEquals(-1.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-1.0, glucoseStatus.delta, 0.001)
@ -61,7 +60,7 @@ class GlucoseStatusTest : TestBase() {
} }
@Test fun oneRecordShouldProduceZeroDeltas() { @Test fun oneRecordShouldProduceZeroDeltas() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOneCurrentRecordBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData())
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001) Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001)
Assert.assertEquals(0.0, glucoseStatus.delta, 0.001) Assert.assertEquals(0.0, glucoseStatus.delta, 0.001)
@ -71,19 +70,19 @@ class GlucoseStatusTest : TestBase() {
} }
@Test fun insufficientDataShouldReturnNull() { @Test fun insufficientDataShouldReturnNull() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateInsufficientBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateInsufficientBgData())
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
Assert.assertEquals(null, glucoseStatus) Assert.assertEquals(null, glucoseStatus)
} }
@Test fun oldDataShouldReturnNull() { @Test fun oldDataShouldReturnNull() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
Assert.assertEquals(null, glucoseStatus) Assert.assertEquals(null, glucoseStatus)
} }
@Test fun returnOldDataIfAllowed() { @Test fun returnOldDataIfAllowed() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateOldBgData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true) val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true)
Assert.assertNotEquals(null, glucoseStatus) Assert.assertNotEquals(null, glucoseStatus)
} }
@ -93,7 +92,7 @@ class GlucoseStatusTest : TestBase() {
} }
@Test fun calculateGlucoseStatusForLibreTestBgData() { @Test fun calculateGlucoseStatusForLibreTestBgData() {
PowerMockito.`when`(iobCobCalculatorPlugin.bgReadings).thenReturn(generateLibreTestData()) PowerMockito.`when`(iobCobCalculatorPlugin.getBgReadingsDataTableCopy()).thenReturn(generateLibreTestData())
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!! val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
Assert.assertEquals(100.0, glucoseStatus.glucose, 0.001) // Assert.assertEquals(100.0, glucoseStatus.glucose, 0.001) //
Assert.assertEquals(-10.0, glucoseStatus.delta, 0.001) Assert.assertEquals(-10.0, glucoseStatus.delta, 0.001)
@ -105,7 +104,6 @@ class GlucoseStatusTest : TestBase() {
@Before @Before
fun initMocking() { fun initMocking() {
PowerMockito.`when`(dateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()) 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}] // [{"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}]