lift out flat BG check from determinebasal to BgQualityCheckPlugin
This commit is contained in:
parent
1f1a2eae48
commit
d5af299692
21 changed files with 197 additions and 94 deletions
|
@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||||
import info.nightscout.database.impl.AppRepository
|
import info.nightscout.database.impl.AppRepository
|
||||||
import info.nightscout.implementation.constraints.ConstraintsImpl
|
import info.nightscout.implementation.constraints.ConstraintsImpl
|
||||||
|
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
import info.nightscout.interfaces.constraints.Constraints
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.constraints.Objectives
|
import info.nightscout.interfaces.constraints.Objectives
|
||||||
|
@ -71,6 +72,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
@Mock lateinit var profileInstantiator: ProfileInstantiator
|
@Mock lateinit var profileInstantiator: ProfileInstantiator
|
||||||
@Mock lateinit var danaHistoryDatabase: DanaHistoryDatabase
|
@Mock lateinit var danaHistoryDatabase: DanaHistoryDatabase
|
||||||
@Mock lateinit var insightDatabase: InsightDatabase
|
@Mock lateinit var insightDatabase: InsightDatabase
|
||||||
|
@Mock lateinit var bgQualityCheck: BgQualityCheck
|
||||||
|
|
||||||
private lateinit var hardLimits: HardLimits
|
private lateinit var hardLimits: HardLimits
|
||||||
private lateinit var danaPump: DanaPump
|
private lateinit var danaPump: DanaPump
|
||||||
|
@ -182,7 +184,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
sp,
|
sp,
|
||||||
dateUtil,
|
dateUtil,
|
||||||
repository,
|
repository,
|
||||||
glucoseStatusProvider
|
glucoseStatusProvider,
|
||||||
|
bgQualityCheck
|
||||||
)
|
)
|
||||||
openAPSSMBDynamicISFPlugin =
|
openAPSSMBDynamicISFPlugin =
|
||||||
OpenAPSSMBDynamicISFPlugin(
|
OpenAPSSMBDynamicISFPlugin(
|
||||||
|
@ -201,7 +204,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||||
dateUtil,
|
dateUtil,
|
||||||
repository,
|
repository,
|
||||||
glucoseStatusProvider,
|
glucoseStatusProvider,
|
||||||
config
|
config,
|
||||||
|
bgQualityCheck
|
||||||
)
|
)
|
||||||
openAPSAMAPlugin =
|
openAPSAMAPlugin =
|
||||||
OpenAPSAMAPlugin(
|
OpenAPSAMAPlugin(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.androidaps.TestBaseWithProfile
|
||||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||||
import info.nightscout.database.impl.AppRepository
|
import info.nightscout.database.impl.AppRepository
|
||||||
import info.nightscout.interfaces.Constants
|
import info.nightscout.interfaces.Constants
|
||||||
|
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
import info.nightscout.interfaces.constraints.Constraints
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
|
@ -37,6 +38,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
||||||
@Mock lateinit var profiler: Profiler
|
@Mock lateinit var profiler: Profiler
|
||||||
@Mock lateinit var repository: AppRepository
|
@Mock lateinit var repository: AppRepository
|
||||||
@Mock lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
@Mock lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||||
|
@Mock lateinit var bgQualityCheck: BgQualityCheck
|
||||||
|
|
||||||
private lateinit var hardLimits: HardLimits
|
private lateinit var hardLimits: HardLimits
|
||||||
private lateinit var safetyPlugin: SafetyPlugin
|
private lateinit var safetyPlugin: SafetyPlugin
|
||||||
|
@ -80,7 +82,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
||||||
)
|
)
|
||||||
openAPSSMBPlugin = OpenAPSSMBPlugin(
|
openAPSSMBPlugin = OpenAPSSMBPlugin(
|
||||||
injector, aapsLogger, rxBus, constraintChecker, rh, profileFunction, context, activePlugin, iobCobCalculator, hardLimits, profiler, sp,
|
injector, aapsLogger, rxBus, constraintChecker, rh, profileFunction, context, activePlugin, iobCobCalculator, hardLimits, profiler, sp,
|
||||||
dateUtil, repository, glucoseStatusProvider
|
dateUtil, repository, glucoseStatusProvider, bgQualityCheck
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface DetermineBasalAdapter {
|
||||||
microBolusAllowed: Boolean = false,
|
microBolusAllowed: Boolean = false,
|
||||||
uamAllowed: Boolean = false,
|
uamAllowed: Boolean = false,
|
||||||
advancedFiltering: Boolean = false,
|
advancedFiltering: Boolean = false,
|
||||||
isSaveCgmSource: Boolean = false
|
flatBGsDetected: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
operator fun invoke(): APSResult?
|
operator fun invoke(): APSResult?
|
||||||
|
|
|
@ -3,6 +3,15 @@ package info.nightscout.interfaces.bgQualityCheck
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
|
||||||
interface BgQualityCheck {
|
interface BgQualityCheck {
|
||||||
|
enum class State {
|
||||||
|
UNKNOWN,
|
||||||
|
FIVE_MIN_DATA,
|
||||||
|
RECALCULATED,
|
||||||
|
DOUBLED,
|
||||||
|
FLAT // stale data for 45 min
|
||||||
|
}
|
||||||
|
|
||||||
|
var state: State
|
||||||
var message: String
|
var message: String
|
||||||
@DrawableRes fun icon(): Int
|
@DrawableRes fun icon(): Int
|
||||||
fun stateDescription(): String
|
fun stateDescription(): String
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package info.nightscout.interfaces.source
|
||||||
|
|
||||||
|
interface DexcomBoyda
|
|
@ -110,7 +110,7 @@ function enable_smb(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, isSaveCgmSource) {
|
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, flatBGsDetected) {
|
||||||
var rT = {}; //short for requestedTemp
|
var rT = {}; //short for requestedTemp
|
||||||
|
|
||||||
var deliverAt = new Date();
|
var deliverAt = new Date();
|
||||||
|
@ -142,16 +142,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
||||||
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
|
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
|
||||||
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
||||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
} else if ( bg > 60 && flatBGsDetected) {
|
||||||
} else if ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 && !isSaveCgmSource) {
|
|
||||||
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||||
rT.reason = "CGM was just calibrated";
|
rT.reason = "CGM was just calibrated";
|
||||||
} else {
|
} else {
|
||||||
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && flatBGsDetected )) {
|
||||||
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) && !isSaveCgmSource ) {
|
|
||||||
if (currenttemp.rate > basal) { // high temp is running
|
if (currenttemp.rate > basal) { // high temp is running
|
||||||
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||||
rT.deliverAt = deliverAt;
|
rT.deliverAt = deliverAt;
|
||||||
|
|
|
@ -110,7 +110,7 @@ function enable_smb(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, isSaveCgmSource) {
|
var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, autosens_data, meal_data, tempBasalFunctions, microBolusAllowed, reservoir_data, currentTime, flatBGsDetected) {
|
||||||
var rT = {}; //short for requestedTemp
|
var rT = {}; //short for requestedTemp
|
||||||
|
|
||||||
var deliverAt = new Date();
|
var deliverAt = new Date();
|
||||||
|
@ -142,16 +142,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
||||||
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
if (minAgo > 12 || minAgo < -5) { // Dexcom data is too old, or way in the future
|
||||||
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
|
rT.reason = "If current system time "+systemTime+" is correct, then BG data is too old. The last BG data was read "+minAgo+"m ago at "+bgTime;
|
||||||
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
// if BG is too old/noisy, or is changing less than 1 mg/dL/5m for 45m, cancel any high temps and shorten any long zero temps
|
||||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
} else if ( bg > 60 && flatBGsDetected) {
|
||||||
} else if ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 && !isSaveCgmSource) {
|
|
||||||
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||||
rT.reason = "CGM was just calibrated";
|
rT.reason = "CGM was just calibrated";
|
||||||
} else {
|
} else {
|
||||||
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
rT.reason = "Error: CGM data is unchanged for the past ~45m";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && flatBGsDetected )) {
|
||||||
if (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && glucose_status.delta == 0 && glucose_status.short_avgdelta > -1 && glucose_status.short_avgdelta < 1 && glucose_status.long_avgdelta > -1 && glucose_status.long_avgdelta < 1 ) && !isSaveCgmSource ) {
|
|
||||||
if (currenttemp.rate > basal) { // high temp is running
|
if (currenttemp.rate > basal) { // high temp is running
|
||||||
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||||
rT.deliverAt = deliverAt;
|
rT.deliverAt = deliverAt;
|
||||||
|
|
|
@ -162,7 +162,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
||||||
microBolusAllowed: Boolean,
|
microBolusAllowed: Boolean,
|
||||||
uamAllowed: Boolean,
|
uamAllowed: Boolean,
|
||||||
advancedFiltering: Boolean,
|
advancedFiltering: Boolean,
|
||||||
isSaveCgmSource: Boolean
|
flatBGsDetected: Boolean
|
||||||
) {
|
) {
|
||||||
this.profile = JSONObject()
|
this.profile = JSONObject()
|
||||||
this.profile.put("max_iob", maxIob)
|
this.profile.put("max_iob", maxIob)
|
||||||
|
|
|
@ -57,7 +57,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
private var microBolusAllowed = false
|
private var microBolusAllowed = false
|
||||||
private var smbAlwaysAllowed = false
|
private var smbAlwaysAllowed = false
|
||||||
private var currentTime: Long = 0
|
private var currentTime: Long = 0
|
||||||
private var saveCgmSource = false
|
private var flatBGsDetected = false
|
||||||
|
|
||||||
override var currentTempParam: String? = null
|
override var currentTempParam: String? = null
|
||||||
override var iobDataParam: String? = null
|
override var iobDataParam: String? = null
|
||||||
|
@ -79,7 +79,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected")
|
||||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||||
val rhino = Context.enter()
|
val rhino = Context.enter()
|
||||||
val scope: Scriptable = rhino.initStandardObjects()
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
@ -119,7 +119,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
java.lang.Boolean.valueOf(microBolusAllowed),
|
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||||
java.lang.Long.valueOf(currentTime),
|
java.lang.Long.valueOf(currentTime),
|
||||||
java.lang.Boolean.valueOf(saveCgmSource)
|
java.lang.Boolean.valueOf(flatBGsDetected)
|
||||||
)
|
)
|
||||||
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||||
scriptDebug = LoggerCallback.scriptDebug
|
scriptDebug = LoggerCallback.scriptDebug
|
||||||
|
@ -174,7 +174,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
microBolusAllowed: Boolean,
|
microBolusAllowed: Boolean,
|
||||||
uamAllowed: Boolean,
|
uamAllowed: Boolean,
|
||||||
advancedFiltering: Boolean,
|
advancedFiltering: Boolean,
|
||||||
isSaveCgmSource: Boolean
|
flatBGsDetected: Boolean
|
||||||
) {
|
) {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||||
|
@ -262,7 +262,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
||||||
this.microBolusAllowed = microBolusAllowed
|
this.microBolusAllowed = microBolusAllowed
|
||||||
smbAlwaysAllowed = advancedFiltering
|
smbAlwaysAllowed = advancedFiltering
|
||||||
currentTime = now
|
currentTime = now
|
||||||
saveCgmSource = isSaveCgmSource
|
this.flatBGsDetected = flatBGsDetected
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import info.nightscout.interfaces.aps.APS
|
||||||
import info.nightscout.interfaces.aps.AutosensResult
|
import info.nightscout.interfaces.aps.AutosensResult
|
||||||
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
||||||
import info.nightscout.interfaces.aps.SMBDefaults
|
import info.nightscout.interfaces.aps.SMBDefaults
|
||||||
|
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
import info.nightscout.interfaces.constraints.Constraints
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||||
|
@ -55,7 +56,8 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
private val repository: AppRepository,
|
private val repository: AppRepository,
|
||||||
private val glucoseStatusProvider: GlucoseStatusProvider
|
private val glucoseStatusProvider: GlucoseStatusProvider,
|
||||||
|
private val bgQualityCheck: BgQualityCheck
|
||||||
) : PluginBase(
|
) : PluginBase(
|
||||||
PluginDescription()
|
PluginDescription()
|
||||||
.mainType(PluginType.APS)
|
.mainType(PluginType.APS)
|
||||||
|
@ -191,6 +193,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
constraintChecker.isUAMEnabled(it)
|
constraintChecker.isUAMEnabled(it)
|
||||||
inputConstraints.copyReasons(it)
|
inputConstraints.copyReasons(it)
|
||||||
}
|
}
|
||||||
|
val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT
|
||||||
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||||
profiler.log(LTag.APS, "SMB data gathering", start)
|
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||||
start = System.currentTimeMillis()
|
start = System.currentTimeMillis()
|
||||||
|
@ -207,7 +210,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
smbAllowed.value(),
|
smbAllowed.value(),
|
||||||
uam.value(),
|
uam.value(),
|
||||||
advancedFiltering.value(),
|
advancedFiltering.value(),
|
||||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin"
|
flatBGsDetected
|
||||||
)
|
)
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||||
|
|
|
@ -59,7 +59,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
||||||
private var microBolusAllowed = false
|
private var microBolusAllowed = false
|
||||||
private var smbAlwaysAllowed = false
|
private var smbAlwaysAllowed = false
|
||||||
private var currentTime: Long = 0
|
private var currentTime: Long = 0
|
||||||
private var saveCgmSource = false
|
private var flatBGsDetected = false
|
||||||
|
|
||||||
override var currentTempParam: String? = null
|
override var currentTempParam: String? = null
|
||||||
override var iobDataParam: String? = null
|
override var iobDataParam: String? = null
|
||||||
|
@ -81,7 +81,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
||||||
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
aapsLogger.debug(LTag.APS, "MicroBolusAllowed: $microBolusAllowed")
|
||||||
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
aapsLogger.debug(LTag.APS, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected")
|
||||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||||
val rhino = Context.enter()
|
val rhino = Context.enter()
|
||||||
val scope: Scriptable = rhino.initStandardObjects()
|
val scope: Scriptable = rhino.initStandardObjects()
|
||||||
|
@ -121,7 +121,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
||||||
java.lang.Boolean.valueOf(microBolusAllowed),
|
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||||
java.lang.Long.valueOf(currentTime),
|
java.lang.Long.valueOf(currentTime),
|
||||||
java.lang.Boolean.valueOf(saveCgmSource)
|
java.lang.Boolean.valueOf(flatBGsDetected)
|
||||||
)
|
)
|
||||||
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
|
||||||
scriptDebug = LoggerCallback.scriptDebug
|
scriptDebug = LoggerCallback.scriptDebug
|
||||||
|
@ -176,7 +176,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
||||||
microBolusAllowed: Boolean,
|
microBolusAllowed: Boolean,
|
||||||
uamAllowed: Boolean,
|
uamAllowed: Boolean,
|
||||||
advancedFiltering: Boolean,
|
advancedFiltering: Boolean,
|
||||||
isSaveCgmSource: Boolean
|
flatBGsDetected: Boolean
|
||||||
) {
|
) {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||||
|
@ -312,7 +312,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
||||||
this.microBolusAllowed = microBolusAllowed
|
this.microBolusAllowed = microBolusAllowed
|
||||||
smbAlwaysAllowed = advancedFiltering
|
smbAlwaysAllowed = advancedFiltering
|
||||||
currentTime = now
|
currentTime = now
|
||||||
saveCgmSource = isSaveCgmSource
|
this.flatBGsDetected = flatBGsDetected
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||||
import info.nightscout.database.impl.AppRepository
|
import info.nightscout.database.impl.AppRepository
|
||||||
import info.nightscout.interfaces.Config
|
import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
||||||
|
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraints
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
|
@ -42,7 +43,8 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
||||||
dateUtil: DateUtil,
|
dateUtil: DateUtil,
|
||||||
repository: AppRepository,
|
repository: AppRepository,
|
||||||
glucoseStatusProvider: GlucoseStatusProvider,
|
glucoseStatusProvider: GlucoseStatusProvider,
|
||||||
private val config: Config
|
private val config: Config,
|
||||||
|
private val bgQualityCheck: BgQualityCheck
|
||||||
) : OpenAPSSMBPlugin(
|
) : OpenAPSSMBPlugin(
|
||||||
injector,
|
injector,
|
||||||
aapsLogger,
|
aapsLogger,
|
||||||
|
@ -58,7 +60,8 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
||||||
sp,
|
sp,
|
||||||
dateUtil,
|
dateUtil,
|
||||||
repository,
|
repository,
|
||||||
glucoseStatusProvider
|
glucoseStatusProvider,
|
||||||
|
bgQualityCheck
|
||||||
) {
|
) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
|
@ -41,17 +41,11 @@ class AidexPlugin @Inject constructor(
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
), BgSource {
|
), BgSource {
|
||||||
|
|
||||||
private var advancedFiltering = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aidex App doesn't have upload to NS
|
* Aidex App doesn't have upload to NS
|
||||||
*/
|
*/
|
||||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = true
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = true
|
||||||
|
|
||||||
override fun advancedFilteringSupported(): Boolean {
|
|
||||||
return advancedFiltering
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow only for pumpcontrol or dev & engineering_mode
|
// Allow only for pumpcontrol or dev & engineering_mode
|
||||||
override fun specialEnableCondition(): Boolean {
|
override fun specialEnableCondition(): Boolean {
|
||||||
return config.APS.not() || config.isDev() && config.isEngineeringMode()
|
return config.APS.not() || config.isDev() && config.isEngineeringMode()
|
||||||
|
|
|
@ -27,6 +27,7 @@ import info.nightscout.interfaces.plugin.PluginDescription
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
import info.nightscout.interfaces.profile.Profile
|
import info.nightscout.interfaces.profile.Profile
|
||||||
import info.nightscout.interfaces.source.BgSource
|
import info.nightscout.interfaces.source.BgSource
|
||||||
|
import info.nightscout.interfaces.source.DexcomBoyda
|
||||||
import info.nightscout.plugins.R
|
import info.nightscout.plugins.R
|
||||||
import info.nightscout.plugins.source.activities.RequestDexcomPermissionActivity
|
import info.nightscout.plugins.source.activities.RequestDexcomPermissionActivity
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
@ -58,7 +59,7 @@ class DexcomPlugin @Inject constructor(
|
||||||
.preferencesId(R.xml.pref_dexcom)
|
.preferencesId(R.xml.pref_dexcom)
|
||||||
.description(R.string.description_source_dexcom),
|
.description(R.string.description_source_dexcom),
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
), BgSource {
|
), BgSource, DexcomBoyda {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (!config.NSCLIENT) {
|
if (!config.NSCLIENT) {
|
||||||
|
@ -66,9 +67,7 @@ class DexcomPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun advancedFilteringSupported(): Boolean {
|
override fun advancedFilteringSupported(): Boolean = true
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
||||||
(glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE ||
|
(glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE ||
|
||||||
|
|
|
@ -64,9 +64,7 @@ class NSClientSourcePlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun advancedFilteringSupported(): Boolean {
|
override fun advancedFilteringSupported(): Boolean = isAdvancedFilteringEnabled
|
||||||
return isAdvancedFilteringEnabled
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
|
||||||
|
|
||||||
|
|
|
@ -73,9 +73,7 @@ class RandomBgPlugin @Inject constructor(
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
override fun advancedFilteringSupported(): Boolean {
|
override fun advancedFilteringSupported(): Boolean = true
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
||||||
glucoseValue.sourceSensor == GlucoseValue.SourceSensor.RANDOM && sp.getBoolean(info.nightscout.core.utils.R.string.key_do_ns_upload, false)
|
glucoseValue.sourceSensor == GlucoseValue.SourceSensor.RANDOM && sp.getBoolean(info.nightscout.core.utils.R.string.key_do_ns_upload, false)
|
||||||
|
|
|
@ -43,9 +43,7 @@ class XdripPlugin @Inject constructor(
|
||||||
|
|
||||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
|
||||||
|
|
||||||
override fun advancedFilteringSupported(): Boolean {
|
override fun advancedFilteringSupported(): Boolean = advancedFiltering
|
||||||
return advancedFiltering
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun detectSource(glucoseValue: GlucoseValue) {
|
private fun detectSource(glucoseValue: GlucoseValue) {
|
||||||
advancedFiltering = arrayOf(
|
advancedFiltering = arrayOf(
|
||||||
|
|
|
@ -7,9 +7,11 @@ import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
import info.nightscout.interfaces.constraints.Constraints
|
import info.nightscout.interfaces.constraints.Constraints
|
||||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||||
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
import info.nightscout.interfaces.plugin.PluginBase
|
import info.nightscout.interfaces.plugin.PluginBase
|
||||||
import info.nightscout.interfaces.plugin.PluginDescription
|
import info.nightscout.interfaces.plugin.PluginDescription
|
||||||
import info.nightscout.interfaces.plugin.PluginType
|
import info.nightscout.interfaces.plugin.PluginType
|
||||||
|
import info.nightscout.interfaces.source.DexcomBoyda
|
||||||
import info.nightscout.plugins.support.R
|
import info.nightscout.plugins.support.R
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
@ -36,7 +38,8 @@ class BgQualityCheckPlugin @Inject constructor(
|
||||||
private val aapsSchedulers:
|
private val aapsSchedulers:
|
||||||
AapsSchedulers,
|
AapsSchedulers,
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val dateUtil: DateUtil
|
private val dateUtil: DateUtil,
|
||||||
|
private val activePlugin: ActivePlugin
|
||||||
) : PluginBase(
|
) : PluginBase(
|
||||||
PluginDescription()
|
PluginDescription()
|
||||||
.mainType(PluginType.CONSTRAINTS)
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
|
@ -49,13 +52,6 @@ class BgQualityCheckPlugin @Inject constructor(
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
enum class State {
|
|
||||||
UNKNOWN,
|
|
||||||
FIVE_MIN_DATA,
|
|
||||||
RECALCULATED,
|
|
||||||
DOUBLED
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
|
@ -69,51 +65,83 @@ class BgQualityCheckPlugin @Inject constructor(
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
var state: State = State.UNKNOWN
|
override var state: BgQualityCheck.State = BgQualityCheck.State.UNKNOWN
|
||||||
override var message: String = ""
|
override var message: String = ""
|
||||||
|
|
||||||
// Fallback to LGS if BG values are doubled
|
// Fallback to LGS if BG values are doubled
|
||||||
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
|
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
|
||||||
if (state == State.DOUBLED)
|
if (state == BgQualityCheck.State.DOUBLED)
|
||||||
maxIob.set(aapsLogger, 0.0, "Doubled values in BGSource", this)
|
maxIob.set(aapsLogger, 0.0, "Doubled values in BGSource", this)
|
||||||
else
|
else
|
||||||
maxIob
|
maxIob
|
||||||
|
|
||||||
@Suppress("CascadeIf") fun processBgData() {
|
fun processBgData() {
|
||||||
val readings = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
val readings = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
||||||
for (i in readings.indices)
|
for (i in readings.indices)
|
||||||
// Deltas are calculated from last ~50 min. Detect RED state only on this interval
|
// Deltas are calculated from last ~50 min. Detect RED state only on this interval
|
||||||
if (i < min(readings.size - 2, 10))
|
if (i < min(readings.size - 2, 10))
|
||||||
if (abs(readings[i].timestamp - readings[i + 1].timestamp) <= T.secs(20).msecs()) {
|
if (abs(readings[i].timestamp - readings[i + 1].timestamp) <= T.secs(20).msecs()) {
|
||||||
state = State.DOUBLED
|
state = BgQualityCheck.State.DOUBLED
|
||||||
aapsLogger.debug(LTag.CORE, "BG similar. Turning on red state.\n${readings[i]}\n${readings[i + 1]}")
|
aapsLogger.debug(LTag.CORE, "BG similar. Turning on red state.\n${readings[i]}\n${readings[i + 1]}")
|
||||||
message = rh.gs(R.string.bg_too_close, dateUtil.dateAndTimeAndSecondsString(readings[i].timestamp), dateUtil.dateAndTimeAndSecondsString(readings[i + 1].timestamp))
|
message = rh.gs(R.string.bg_too_close, dateUtil.dateAndTimeAndSecondsString(readings[i].timestamp), dateUtil.dateAndTimeAndSecondsString(readings[i + 1].timestamp))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (iobCobCalculator.ads.lastUsed5minCalculation == true) {
|
if (activePlugin.activeBgSource !is DexcomBoyda && isBgFlatForInterval(staleBgCheckPeriodMinutes, staleBgMaxDeltaMgdl) == true) {
|
||||||
state = State.FIVE_MIN_DATA
|
state = BgQualityCheck.State.FLAT
|
||||||
|
message = rh.gs(R.string.a11y_bg_quality_flat)
|
||||||
|
} else if (iobCobCalculator.ads.lastUsed5minCalculation == true) {
|
||||||
|
state = BgQualityCheck.State.FIVE_MIN_DATA
|
||||||
message = "Data is clean"
|
message = "Data is clean"
|
||||||
} else if (iobCobCalculator.ads.lastUsed5minCalculation == false) {
|
} else if (iobCobCalculator.ads.lastUsed5minCalculation == false) {
|
||||||
state = State.RECALCULATED
|
state = BgQualityCheck.State.RECALCULATED
|
||||||
message = rh.gs(R.string.recalculated_data_used)
|
message = rh.gs(R.string.recalculated_data_used)
|
||||||
} else {
|
} else {
|
||||||
state = State.UNKNOWN
|
state = BgQualityCheck.State.UNKNOWN
|
||||||
message = ""
|
message = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inspired by @justmara
|
||||||
|
@Suppress("SpellCheckingInspection", "SameParameterValue")
|
||||||
|
private fun isBgFlatForInterval(minutes: Long, maxDelta: Double): Boolean? {
|
||||||
|
val data = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
||||||
|
val lastBg = iobCobCalculator.ads.lastBg()?.value
|
||||||
|
val now = dateUtil.now()
|
||||||
|
val offset = now - T.mins(minutes).msecs()
|
||||||
|
val sizeRecords = data.size
|
||||||
|
|
||||||
|
lastBg ?: return null
|
||||||
|
if (sizeRecords < 5) return null // not enough data
|
||||||
|
if (data[data.size - 1].timestamp > now - 45 * 60 * 1000L) return null // data too fresh to detect
|
||||||
|
if (data[0].timestamp < now - 7 * 60 * 1000L) return null // data is old
|
||||||
|
|
||||||
|
for (bg in data) {
|
||||||
|
if (bg.timestamp < offset) break
|
||||||
|
if (abs(lastBg - bg.value) > maxDelta) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
@DrawableRes override fun icon(): Int =
|
@DrawableRes override fun icon(): Int =
|
||||||
when (state) {
|
when (state) {
|
||||||
State.UNKNOWN -> 0
|
BgQualityCheck.State.UNKNOWN -> 0
|
||||||
State.FIVE_MIN_DATA -> 0
|
BgQualityCheck.State.FIVE_MIN_DATA -> 0
|
||||||
State.RECALCULATED -> R.drawable.ic_baseline_warning_24_yellow
|
BgQualityCheck.State.RECALCULATED -> R.drawable.ic_baseline_warning_24_yellow
|
||||||
State.DOUBLED -> R.drawable.ic_baseline_warning_24_red
|
BgQualityCheck.State.DOUBLED -> R.drawable.ic_baseline_warning_24_red
|
||||||
|
BgQualityCheck.State.FLAT -> R.drawable.ic_baseline_trending_flat_24
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stateDescription(): String =
|
override fun stateDescription(): String =
|
||||||
when (state) {
|
when (state) {
|
||||||
State.RECALCULATED -> rh.gs(R.string.a11y_bg_quality_recalculated)
|
BgQualityCheck.State.RECALCULATED -> rh.gs(R.string.a11y_bg_quality_recalculated)
|
||||||
State.DOUBLED -> rh.gs(R.string.a11y_bg_quality_doubles)
|
BgQualityCheck.State.DOUBLED -> rh.gs(R.string.a11y_bg_quality_doubles)
|
||||||
|
BgQualityCheck.State.FLAT -> rh.gs(R.string.a11y_bg_quality_flat)
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val staleBgCheckPeriodMinutes = 45L
|
||||||
|
const val staleBgMaxDeltaMgdl = 1.0
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FF0000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M22,12l-4,-4v3H3v2h15v3z"/>
|
||||||
|
</vector>
|
|
@ -39,5 +39,6 @@
|
||||||
<string name="bg_too_close">BG too close:\n%1$s\n%2$s</string>
|
<string name="bg_too_close">BG too close:\n%1$s\n%2$s</string>
|
||||||
<string name="a11y_bg_quality_recalculated">recalculated</string>
|
<string name="a11y_bg_quality_recalculated">recalculated</string>
|
||||||
<string name="a11y_bg_quality_doubles">double entries</string>
|
<string name="a11y_bg_quality_doubles">double entries</string>
|
||||||
|
<string name="a11y_bg_quality_flat">Flat data. Considered to be wrong</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -6,14 +6,18 @@ import info.nightscout.androidaps.TestBase
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
import info.nightscout.database.entities.GlucoseValue
|
import info.nightscout.database.entities.GlucoseValue
|
||||||
import info.nightscout.interfaces.aps.AutosensDataStore
|
import info.nightscout.interfaces.aps.AutosensDataStore
|
||||||
|
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||||
import info.nightscout.interfaces.constraints.Constraint
|
import info.nightscout.interfaces.constraints.Constraint
|
||||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||||
|
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||||
|
import info.nightscout.interfaces.source.BgSource
|
||||||
|
import info.nightscout.interfaces.source.DexcomBoyda
|
||||||
import info.nightscout.plugins.support.R
|
import info.nightscout.plugins.support.R
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtil
|
||||||
import info.nightscout.shared.utils.T
|
import info.nightscout.shared.utils.T
|
||||||
import org.junit.Assert
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.ArgumentMatchers.any
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
@ -28,10 +32,12 @@ class BgQualityCheckPluginTest : TestBase() {
|
||||||
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Mock lateinit var dateUtil: DateUtil
|
@Mock lateinit var dateUtil: DateUtil
|
||||||
@Mock lateinit var autosensDataStore: AutosensDataStore
|
@Mock lateinit var autosensDataStore: AutosensDataStore
|
||||||
|
@Mock lateinit var activePlugin: ActivePlugin
|
||||||
|
|
||||||
private lateinit var plugin: BgQualityCheckPlugin
|
private lateinit var plugin: BgQualityCheckPlugin
|
||||||
|
|
||||||
val injector = HasAndroidInjector { AndroidInjector { } }
|
private val injector = HasAndroidInjector { AndroidInjector { } }
|
||||||
|
val now = 100000000L
|
||||||
//private val autosensDataStore = AutosensDataStoreObject()
|
//private val autosensDataStore = AutosensDataStoreObject()
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@ -45,27 +51,29 @@ class BgQualityCheckPluginTest : TestBase() {
|
||||||
iobCobCalculator,
|
iobCobCalculator,
|
||||||
aapsSchedulers,
|
aapsSchedulers,
|
||||||
fabricPrivacy,
|
fabricPrivacy,
|
||||||
dateUtil
|
dateUtil,
|
||||||
|
activePlugin
|
||||||
)
|
)
|
||||||
`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
||||||
`when`(rh.gs(anyInt())).thenReturn("")
|
`when`(rh.gs(anyInt())).thenReturn("")
|
||||||
`when`(rh.gs(anyInt(), any(), any())).thenReturn("")
|
`when`(rh.gs(anyInt(), any(), any())).thenReturn("")
|
||||||
|
`when`(dateUtil.now()).thenReturn(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun runTest() {
|
fun runTest() {
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(null)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(null)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.UNKNOWN, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.UNKNOWN, plugin.state)
|
||||||
Assert.assertEquals(0, plugin.icon())
|
Assertions.assertEquals(0, plugin.icon())
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.FIVE_MIN_DATA, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.FIVE_MIN_DATA, plugin.state)
|
||||||
Assert.assertEquals(0, plugin.icon())
|
Assertions.assertEquals(0, plugin.icon())
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.RECALCULATED, plugin.state)
|
||||||
Assert.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon())
|
Assertions.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon())
|
||||||
|
|
||||||
val superData: MutableList<GlucoseValue> = ArrayList()
|
val superData: MutableList<GlucoseValue> = ArrayList()
|
||||||
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
@ -76,10 +84,10 @@ class BgQualityCheckPluginTest : TestBase() {
|
||||||
|
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.FIVE_MIN_DATA, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.FIVE_MIN_DATA, plugin.state)
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.RECALCULATED, plugin.state)
|
||||||
|
|
||||||
val duplicatedData: MutableList<GlucoseValue> = ArrayList()
|
val duplicatedData: MutableList<GlucoseValue> = ArrayList()
|
||||||
duplicatedData.add(
|
duplicatedData.add(
|
||||||
|
@ -136,8 +144,8 @@ class BgQualityCheckPluginTest : TestBase() {
|
||||||
|
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.DOUBLED, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.DOUBLED, plugin.state)
|
||||||
Assert.assertEquals(R.drawable.ic_baseline_warning_24_red, plugin.icon())
|
Assertions.assertEquals(R.drawable.ic_baseline_warning_24_red, plugin.icon())
|
||||||
|
|
||||||
val identicalData: MutableList<GlucoseValue> = ArrayList()
|
val identicalData: MutableList<GlucoseValue> = ArrayList()
|
||||||
identicalData.add(
|
identicalData.add(
|
||||||
|
@ -194,19 +202,73 @@ class BgQualityCheckPluginTest : TestBase() {
|
||||||
|
|
||||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
||||||
plugin.processBgData()
|
plugin.processBgData()
|
||||||
Assert.assertEquals(BgQualityCheckPlugin.State.DOUBLED, plugin.state)
|
Assertions.assertEquals(BgQualityCheck.State.DOUBLED, plugin.state)
|
||||||
|
|
||||||
|
// Flat data
|
||||||
|
val flatData: MutableList<GlucoseValue> = ArrayList()
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow
|
||||||
|
.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 101.0, timestamp = now + T.mins(-10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-25).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 99.0, timestamp = now + T.mins(-30).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-35).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-40).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-45).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(flatData)
|
||||||
|
`when`(iobCobCalculator.ads.lastBg()).thenReturn(flatData[0])
|
||||||
|
|
||||||
|
// Test non-dexcom plugin on flat data
|
||||||
|
class OtherPlugin : BgSource {
|
||||||
|
|
||||||
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = true
|
||||||
|
}
|
||||||
|
`when`(activePlugin.activeBgSource).thenReturn(OtherPlugin())
|
||||||
|
plugin.processBgData()
|
||||||
|
Assertions.assertEquals(BgQualityCheck.State.FLAT, plugin.state)
|
||||||
|
Assertions.assertEquals(R.drawable.ic_baseline_trending_flat_24, plugin.icon())
|
||||||
|
|
||||||
|
// Test dexcom plugin on flat data
|
||||||
|
class DexcomPlugin : BgSource, DexcomBoyda {
|
||||||
|
|
||||||
|
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = true
|
||||||
|
}
|
||||||
|
`when`(activePlugin.activeBgSource).thenReturn(DexcomPlugin())
|
||||||
|
plugin.processBgData()
|
||||||
|
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state)
|
||||||
|
|
||||||
|
// not enough data
|
||||||
|
val incompleteData: MutableList<GlucoseValue> = ArrayList()
|
||||||
|
incompleteData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
incompleteData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(incompleteData)
|
||||||
|
`when`(iobCobCalculator.ads.lastBg()).thenReturn(incompleteData[0])
|
||||||
|
`when`(activePlugin.activeBgSource).thenReturn(OtherPlugin())
|
||||||
|
plugin.processBgData()// must be more than 5 values
|
||||||
|
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state)
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 101.0, timestamp = now + T.mins(-10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-25).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 99.0, timestamp = now + T.mins(-30).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-35).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
flatData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-40).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
plugin.processBgData() // must be at least 45 min old
|
||||||
|
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun applyMaxIOBConstraintsTest() {
|
fun applyMaxIOBConstraintsTest() {
|
||||||
plugin.state = BgQualityCheckPlugin.State.UNKNOWN
|
plugin.state = BgQualityCheck.State.UNKNOWN
|
||||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||||
plugin.state = BgQualityCheckPlugin.State.FIVE_MIN_DATA
|
plugin.state = BgQualityCheck.State.FIVE_MIN_DATA
|
||||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||||
plugin.state = BgQualityCheckPlugin.State.RECALCULATED
|
plugin.state = BgQualityCheck.State.RECALCULATED
|
||||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||||
plugin.state = BgQualityCheckPlugin.State.DOUBLED
|
plugin.state = BgQualityCheck.State.DOUBLED
|
||||||
Assert.assertEquals(0.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
Assertions.assertEquals(0.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue