BgQualityCheckPlugin
This commit is contained in:
parent
6fb83d4949
commit
2b021ffafc
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
||||||
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
|
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
|
||||||
|
@ -294,6 +295,12 @@ abstract class PluginsModule {
|
||||||
@IntKey(380)
|
@IntKey(380)
|
||||||
abstract fun bindDstHelperPlugin(plugin: DstHelperPlugin): PluginBase
|
abstract fun bindDstHelperPlugin(plugin: DstHelperPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(381)
|
||||||
|
abstract fun bindBgQualityCheckPlugin(plugin: BgQualityCheckPlugin): PluginBase
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@AllConfigs
|
@AllConfigs
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.bgQualityCheck
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class BgQualityCheckPlugin @Inject constructor(
|
||||||
|
injector: HasAndroidInjector,
|
||||||
|
aapsLogger: AAPSLogger,
|
||||||
|
rh: ResourceHelper,
|
||||||
|
private val rxBus: RxBus,
|
||||||
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
|
private val aapsSchedulers: AapsSchedulers,
|
||||||
|
private val fabricPrivacy: FabricPrivacy
|
||||||
|
) : PluginBase(
|
||||||
|
PluginDescription()
|
||||||
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
|
.neverVisible(true)
|
||||||
|
.alwaysEnabled(true)
|
||||||
|
.showInList(false)
|
||||||
|
.pluginName(R.string.dst_plugin_name),
|
||||||
|
aapsLogger, rh, injector
|
||||||
|
), Constraints {
|
||||||
|
|
||||||
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
UNKNOWN,
|
||||||
|
FIVE_MIN_DATA,
|
||||||
|
RECALCULATED,
|
||||||
|
DOUBLED
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventBucketedDataCreated::class.java)
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.subscribe({ processBgData() }, fabricPrivacy::logException)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
var state: State = State.UNKNOWN
|
||||||
|
|
||||||
|
// Return false if BG values are doubled
|
||||||
|
@Suppress("ReplaceGetOrSet")
|
||||||
|
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
|
if (state == State.DOUBLED)
|
||||||
|
value.set(aapsLogger, false, "Doubled values in BGSource", this)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processBgData() {
|
||||||
|
val readings = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
||||||
|
for (i in readings.indices)
|
||||||
|
if (i < readings.size - 2)
|
||||||
|
if (abs(readings[i].timestamp - readings[i + 1].timestamp) <= 1000) {
|
||||||
|
state = State.DOUBLED
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (iobCobCalculator.ads.lastUsed5minCalculation == true)
|
||||||
|
state = State.FIVE_MIN_DATA
|
||||||
|
else if (iobCobCalculator.ads.lastUsed5minCalculation == false)
|
||||||
|
state = State.RECALCULATED
|
||||||
|
else
|
||||||
|
state = State.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
fun icon(): Int =
|
||||||
|
when (state) {
|
||||||
|
State.UNKNOWN -> 0
|
||||||
|
State.FIVE_MIN_DATA -> 0
|
||||||
|
State.RECALCULATED -> R.drawable.ic_baseline_warning_24_yellow
|
||||||
|
State.DOUBLED -> R.drawable.ic_baseline_warning_24_red
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,11 @@ import javax.inject.Singleton
|
||||||
class DstHelperPlugin @Inject constructor(
|
class DstHelperPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private var rxBus: RxBus,
|
private val rxBus: RxBus,
|
||||||
rh: ResourceHelper,
|
rh: ResourceHelper,
|
||||||
private var sp: SP,
|
private val sp: SP,
|
||||||
private var activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private var loopPlugin: LoopPlugin
|
private val loopPlugin: LoopPlugin
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.CONSTRAINTS)
|
.mainType(PluginType.CONSTRAINTS)
|
||||||
.neverVisible(true)
|
.neverVisible(true)
|
||||||
|
@ -41,6 +41,7 @@ class DstHelperPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return false if time to DST change happened in the last 3 hours.
|
//Return false if time to DST change happened in the last 3 hours.
|
||||||
|
@Suppress("ReplaceGetOrSet")
|
||||||
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
|
||||||
val pump = activePlugin.activePump
|
val pump = activePlugin.activePump
|
||||||
if (pump.canHandleDST()) {
|
if (pump.canHandleDST()) {
|
||||||
|
@ -52,9 +53,9 @@ class DstHelperPlugin @Inject constructor(
|
||||||
val snoozedTo: Long = sp.getLong(R.string.key_snooze_dst_in24h, 0L)
|
val snoozedTo: Long = sp.getLong(R.string.key_snooze_dst_in24h, 0L)
|
||||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||||
val notification = NotificationWithAction(injector, Notification.DST_IN_24H, rh.gs(R.string.dst_in_24h_warning), Notification.LOW)
|
val notification = NotificationWithAction(injector, Notification.DST_IN_24H, rh.gs(R.string.dst_in_24h_warning), Notification.LOW)
|
||||||
notification.action(R.string.snooze, Runnable {
|
notification.action(R.string.snooze) {
|
||||||
sp.putLong(R.string.key_snooze_dst_in24h, System.currentTimeMillis() + T.hours(24).msecs())
|
sp.putLong(R.string.key_snooze_dst_in24h, System.currentTimeMillis() + T.hours(24).msecs())
|
||||||
})
|
}
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,9 +68,9 @@ class DstHelperPlugin @Inject constructor(
|
||||||
val snoozedTo: Long = sp.getLong(R.string.key_snooze_loopdisabled, 0L)
|
val snoozedTo: Long = sp.getLong(R.string.key_snooze_loopdisabled, 0L)
|
||||||
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo) {
|
||||||
val notification = NotificationWithAction(injector, Notification.DST_LOOP_DISABLED, rh.gs(R.string.dst_loop_disabled_warning), Notification.LOW)
|
val notification = NotificationWithAction(injector, Notification.DST_LOOP_DISABLED, rh.gs(R.string.dst_loop_disabled_warning), Notification.LOW)
|
||||||
notification.action(R.string.snooze, Runnable {
|
notification.action(R.string.snooze) {
|
||||||
sp.putLong(R.string.key_snooze_loopdisabled, System.currentTimeMillis() + T.hours(24).msecs())
|
sp.putLong(R.string.key_snooze_loopdisabled, System.currentTimeMillis() + T.hours(24).msecs())
|
||||||
})
|
}
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||||
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
|
||||||
|
@ -122,6 +123,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
@Inject lateinit var overviewData: OverviewData
|
@Inject lateinit var overviewData: OverviewData
|
||||||
@Inject lateinit var overviewPlugin: OverviewPlugin
|
@Inject lateinit var overviewPlugin: OverviewPlugin
|
||||||
@Inject lateinit var automationPlugin: AutomationPlugin
|
@Inject lateinit var automationPlugin: AutomationPlugin
|
||||||
|
@Inject lateinit var bgQualityCheckPlugin: BgQualityCheckPlugin
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -661,6 +663,15 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
else binding.infoLayout.bg.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
else binding.infoLayout.bg.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||||
binding.infoLayout.timeAgo.text = dateUtil.minAgo(rh, overviewData.lastBg?.timestamp)
|
binding.infoLayout.timeAgo.text = dateUtil.minAgo(rh, overviewData.lastBg?.timestamp)
|
||||||
binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(overviewData.lastBg?.timestamp) + ")"
|
binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(overviewData.lastBg?.timestamp) + ")"
|
||||||
|
|
||||||
|
val qualityIcon = bgQualityCheckPlugin.icon()
|
||||||
|
if (qualityIcon != 0) {
|
||||||
|
binding.infoLayout.bgQuality.visibility = View.VISIBLE
|
||||||
|
binding.infoLayout.bgQuality.setImageResource(qualityIcon)
|
||||||
|
} else {
|
||||||
|
binding.infoLayout.bgQuality.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewData.Property.PROFILE -> {
|
OverviewData.Property.PROFILE -> {
|
||||||
|
|
|
@ -13,11 +13,8 @@ import info.nightscout.androidaps.interfaces.PluginDescription
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
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.pump.virtual.VirtualPumpPlugin
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.XDripBroadcast
|
import info.nightscout.androidaps.utils.XDripBroadcast
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
|
||||||
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
|
||||||
|
@ -33,20 +30,18 @@ class RandomBgPlugin @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
rh: ResourceHelper,
|
rh: ResourceHelper,
|
||||||
aapsLogger: AAPSLogger,
|
aapsLogger: AAPSLogger,
|
||||||
private val virtualPumpPlugin: VirtualPumpPlugin,
|
|
||||||
private val buildHelper: BuildHelper,
|
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val dateUtil: DateUtil,
|
|
||||||
private val repository: AppRepository,
|
private val repository: AppRepository,
|
||||||
private val xDripBroadcast: XDripBroadcast
|
private val xDripBroadcast: XDripBroadcast
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(
|
||||||
.mainType(PluginType.BGSOURCE)
|
PluginDescription()
|
||||||
.fragmentClass(BGSourceFragment::class.java.name)
|
.mainType(PluginType.BGSOURCE)
|
||||||
.pluginIcon(R.drawable.ic_dice)
|
.fragmentClass(BGSourceFragment::class.java.name)
|
||||||
.pluginName(R.string.randombg)
|
.pluginIcon(R.drawable.ic_dice)
|
||||||
.shortName(R.string.randombg_short)
|
.pluginName(R.string.randombg)
|
||||||
.preferencesId(R.xml.pref_bgsource)
|
.shortName(R.string.randombg_short)
|
||||||
.description(R.string.description_source_randombg),
|
.preferencesId(R.xml.pref_bgsource)
|
||||||
|
.description(R.string.description_source_randombg),
|
||||||
aapsLogger, rh, injector
|
aapsLogger, rh, injector
|
||||||
), BgSource {
|
), BgSource {
|
||||||
|
|
||||||
|
@ -58,7 +53,7 @@ class RandomBgPlugin @Inject constructor(
|
||||||
const val interval = 5L // minutes
|
const val interval = 5L // minutes
|
||||||
const val min = 70 // mgdl
|
const val min = 70 // mgdl
|
||||||
const val max = 190 // mgdl
|
const val max = 190 // mgdl
|
||||||
const val period = 90.0 // minutes
|
const val period = 120.0 // minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -94,15 +89,18 @@ class RandomBgPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNewData() {
|
private fun handleNewData() {
|
||||||
if (!isEnabled(PluginType.BGSOURCE)) return
|
if (!isEnabled()) return
|
||||||
|
|
||||||
val cal = GregorianCalendar()
|
val cal = GregorianCalendar()
|
||||||
val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60
|
val currentMinute = cal[Calendar.MINUTE] + (cal[Calendar.HOUR_OF_DAY] % 2) * 60
|
||||||
val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2
|
val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / period * 2 * PI)) / 2
|
||||||
|
|
||||||
|
cal[Calendar.MILLISECOND] = 0
|
||||||
|
cal[Calendar.SECOND] = 0
|
||||||
|
cal[Calendar.MINUTE] -= cal[Calendar.MINUTE] % 5
|
||||||
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||||
timestamp = dateUtil.now(),
|
timestamp = cal.timeInMillis,
|
||||||
value = bgMgdl,
|
value = bgMgdl,
|
||||||
raw = 0.0,
|
raw = 0.0,
|
||||||
noise = null,
|
noise = null,
|
||||||
|
@ -111,11 +109,11 @@ class RandomBgPlugin @Inject constructor(
|
||||||
)
|
)
|
||||||
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
|
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
|
||||||
.subscribe({ savedValues ->
|
.subscribe({ savedValues ->
|
||||||
savedValues.inserted.forEach {
|
savedValues.inserted.forEach {
|
||||||
xDripBroadcast(it)
|
xDripBroadcast(it)
|
||||||
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
aapsLogger.debug(LTag.DATABASE, "Inserted bg $it")
|
||||||
}
|
}
|
||||||
}, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) }
|
}, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
app/src/main/res/drawable/ic_baseline_warning_24_red.xml
Normal file
5
app/src/main/res/drawable/ic_baseline_warning_24_red.xml
Normal file
|
@ -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="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFF00"
|
||||||
|
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="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
||||||
|
</vector>
|
|
@ -19,6 +19,14 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/bg_quality"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="Blood glucose quality icon"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/delta_large"
|
android:id="@+id/delta_large"
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
package info.nightscout.androidaps.plugins.constraints.bgQualityCheck
|
||||||
|
|
||||||
|
import dagger.android.AndroidInjector
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.TestBase
|
||||||
|
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||||
|
import info.nightscout.androidaps.interfaces.Constraint
|
||||||
|
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensDataStore
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class BgQualityCheckPluginTest : TestBase() {
|
||||||
|
|
||||||
|
@Mock lateinit var rh: ResourceHelper
|
||||||
|
@Mock lateinit var iobCobCalculator: IobCobCalculator
|
||||||
|
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||||
|
|
||||||
|
private lateinit var plugin: BgQualityCheckPlugin
|
||||||
|
|
||||||
|
val injector = HasAndroidInjector { AndroidInjector { } }
|
||||||
|
private val autosensDataStore = AutosensDataStore()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun mock() {
|
||||||
|
plugin = BgQualityCheckPlugin(injector, aapsLogger, rh, RxBus(aapsSchedulers, aapsLogger), iobCobCalculator, aapsSchedulers, fabricPrivacy)
|
||||||
|
Mockito.`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun runTest() {
|
||||||
|
autosensDataStore.lastUsed5minCalculation = null
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.UNKNOWN, plugin.state)
|
||||||
|
Assert.assertEquals(0, plugin.icon())
|
||||||
|
autosensDataStore.lastUsed5minCalculation = true
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.FIVE_MIN_DATA, plugin.state)
|
||||||
|
Assert.assertEquals(0, plugin.icon())
|
||||||
|
autosensDataStore.lastUsed5minCalculation = false
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
||||||
|
Assert.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon())
|
||||||
|
|
||||||
|
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(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||||
|
autosensDataStore.bgReadings = superData
|
||||||
|
|
||||||
|
autosensDataStore.lastUsed5minCalculation = true
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.FIVE_MIN_DATA, plugin.state)
|
||||||
|
autosensDataStore.lastUsed5minCalculation = false
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
||||||
|
|
||||||
|
val duplicatedData: MutableList<GlucoseValue> = ArrayList()
|
||||||
|
duplicatedData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(20).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
duplicatedData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(20).msecs() + 1,
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
duplicatedData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(10).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
duplicatedData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(15).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
duplicatedData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(5).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
autosensDataStore.bgReadings = duplicatedData
|
||||||
|
|
||||||
|
autosensDataStore.lastUsed5minCalculation = true
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.DOUBLED, plugin.state)
|
||||||
|
Assert.assertEquals(R.drawable.ic_baseline_warning_24_red, plugin.icon())
|
||||||
|
|
||||||
|
val identicalData: MutableList<GlucoseValue> = ArrayList()
|
||||||
|
identicalData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(20).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
identicalData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(20).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
identicalData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(10).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
identicalData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(15).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
identicalData.add(
|
||||||
|
GlucoseValue(
|
||||||
|
raw = 0.0,
|
||||||
|
noise = 0.0,
|
||||||
|
value = 100.0,
|
||||||
|
timestamp = T.mins(5).msecs(),
|
||||||
|
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||||
|
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
autosensDataStore.bgReadings = identicalData
|
||||||
|
|
||||||
|
autosensDataStore.lastUsed5minCalculation = false
|
||||||
|
plugin.processBgData()
|
||||||
|
Assert.assertEquals(BgQualityCheckPlugin.State.DOUBLED, plugin.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isLoopInvocationAllowedTest() {
|
||||||
|
plugin.state = BgQualityCheckPlugin.State.UNKNOWN
|
||||||
|
Assert.assertEquals(true, plugin.isLoopInvocationAllowed(Constraint(true)).value())
|
||||||
|
plugin.state = BgQualityCheckPlugin.State.FIVE_MIN_DATA
|
||||||
|
Assert.assertEquals(true, plugin.isLoopInvocationAllowed(Constraint(true)).value())
|
||||||
|
plugin.state = BgQualityCheckPlugin.State.RECALCULATED
|
||||||
|
Assert.assertEquals(true, plugin.isLoopInvocationAllowed(Constraint(true)).value())
|
||||||
|
plugin.state = BgQualityCheckPlugin.State.DOUBLED
|
||||||
|
Assert.assertEquals(false, plugin.isLoopInvocationAllowed(Constraint(true)).value())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import kotlin.math.roundToLong
|
||||||
class AutosensDataStore {
|
class AutosensDataStore {
|
||||||
|
|
||||||
private val dataLock = Any()
|
private val dataLock = Any()
|
||||||
private var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data
|
var lastUsed5minCalculation: Boolean? = null // true if used 5min bucketed data
|
||||||
|
|
||||||
// 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
|
||||||
|
|
Loading…
Reference in a new issue