Merge remote-tracking branch 'origin/dev' into feature/new-sms-command
# Conflicts: # app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt # plugins/main/src/test/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt
This commit is contained in:
commit
812499ea81
124 changed files with 3085 additions and 1400 deletions
|
@ -151,10 +151,6 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
|
|||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ processPreferenceChange(it) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ passwordResetCheck(this) }, fabricPrivacy::logException)
|
||||
if (startWizard() && !isRunningRealPumpTest()) {
|
||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
|
||||
startActivity(Intent(this, SetupWizardActivity::class.java))
|
||||
|
@ -168,6 +164,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
|
|||
androidPermission.notifyForSystemWindowPermissions(this)
|
||||
androidPermission.notifyForBtConnectPermission(this)
|
||||
}
|
||||
passwordResetCheck(this)
|
||||
}
|
||||
|
||||
private fun checkPluginPreferences(viewPager: ViewPager2) {
|
||||
|
|
|
@ -10,10 +10,11 @@ import info.nightscout.androidaps.insight.database.InsightDatabase
|
|||
import info.nightscout.androidaps.insight.database.InsightDatabaseDao
|
||||
import info.nightscout.androidaps.insight.database.InsightDbHelper
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.implementation.constraints.ConstraintsImpl
|
||||
import info.nightscout.interfaces.ApsMode
|
||||
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
|
||||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.constraints.Objectives
|
||||
|
@ -42,9 +43,10 @@ import info.nightscout.plugins.source.GlimpPlugin
|
|||
import info.nightscout.pump.combo.ComboPlugin
|
||||
import info.nightscout.pump.combo.ruffyscripter.RuffyScripter
|
||||
import info.nightscout.pump.dana.DanaPump
|
||||
import info.nightscout.pump.dana.R
|
||||
import info.nightscout.pump.dana.database.DanaHistoryDatabase
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
|
@ -72,6 +74,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
@Mock lateinit var profileInstantiator: ProfileInstantiator
|
||||
@Mock lateinit var danaHistoryDatabase: DanaHistoryDatabase
|
||||
@Mock lateinit var insightDatabase: InsightDatabase
|
||||
@Mock lateinit var bgQualityCheck: BgQualityCheck
|
||||
|
||||
private lateinit var hardLimits: HardLimits
|
||||
private lateinit var danaPump: DanaPump
|
||||
|
@ -130,13 +133,16 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
`when`(rh.gs(info.nightscout.plugins.R.string.objectivenotstarted)).thenReturn("Objective %1\$d not started")
|
||||
|
||||
// RS constructor
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, "")).thenReturn("")
|
||||
`when`(sp.getString(R.string.key_danars_name, "")).thenReturn("")
|
||||
`when`(sp.getString(R.string.key_danars_address, "")).thenReturn("")
|
||||
// R
|
||||
`when`(sp.getString(R.string.key_danar_bt_name, "")).thenReturn("")
|
||||
|
||||
//SafetyPlugin
|
||||
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
|
||||
constraintChecker = ConstraintsImpl(activePlugin)
|
||||
|
||||
val glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil)
|
||||
val glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil)
|
||||
|
||||
hardLimits = HardLimitsMock(sp, rh)
|
||||
insightDbHelper = InsightDbHelper(insightDatabaseDao)
|
||||
|
@ -183,7 +189,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
sp,
|
||||
dateUtil,
|
||||
repository,
|
||||
glucoseStatusProvider
|
||||
glucoseStatusProvider,
|
||||
bgQualityCheck
|
||||
)
|
||||
openAPSSMBDynamicISFPlugin =
|
||||
OpenAPSSMBDynamicISFPlugin(
|
||||
|
@ -202,7 +209,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
dateUtil,
|
||||
repository,
|
||||
glucoseStatusProvider,
|
||||
config
|
||||
config,
|
||||
bgQualityCheck
|
||||
)
|
||||
openAPSAMAPlugin =
|
||||
OpenAPSAMAPlugin(
|
||||
|
@ -257,9 +265,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
comboPlugin.setPluginEnabled(PluginType.PUMP, true)
|
||||
comboPlugin.setValidBasalRateProfileSelectedOnPump(false)
|
||||
val c = constraintChecker.isLoopInvocationAllowed()
|
||||
Assert.assertEquals(true, c.reasonList.size == 2) // Combo & Objectives
|
||||
Assert.assertEquals(true, c.mostLimitedReasonList.size == 2) // Combo & Objectives
|
||||
Assert.assertEquals(java.lang.Boolean.FALSE, c.value())
|
||||
Assertions.assertEquals(true, c.reasonList.size == 2) // Combo & Objectives
|
||||
Assertions.assertEquals(true, c.mostLimitedReasonList.size == 2) // Combo & Objectives
|
||||
Assertions.assertEquals(java.lang.Boolean.FALSE, c.value())
|
||||
}
|
||||
|
||||
// Safety & Objectives
|
||||
|
@ -270,13 +278,13 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
objectivesPlugin.objectives[Objectives.MAXIOB_ZERO_CL_OBJECTIVE].startedOn = 0
|
||||
var c: Constraint<Boolean> = constraintChecker.isClosedLoopAllowed()
|
||||
aapsLogger.debug("Reason list: " + c.reasonList.toString())
|
||||
// Assert.assertTrue(c.reasonList[0].toString().contains("Closed loop is disabled")) // Safety & Objectives
|
||||
Assert.assertEquals(false, c.value())
|
||||
// Assertions.assertTrue(c.reasonList[0].toString().contains("Closed loop is disabled")) // Safety & Objectives
|
||||
Assertions.assertEquals(false, c.value())
|
||||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("open")
|
||||
c = constraintChecker.isClosedLoopAllowed()
|
||||
Assert.assertTrue(c.reasonList[0].contains("Closed loop mode disabled in preferences")) // Safety & Objectives
|
||||
// Assert.assertEquals(3, c.reasonList.size) // 2x Safety & Objectives
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertTrue(c.reasonList[0].contains("Closed loop mode disabled in preferences")) // Safety & Objectives
|
||||
// Assertions.assertEquals(3, c.reasonList.size) // 2x Safety & Objectives
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
// Safety & Objectives
|
||||
|
@ -286,9 +294,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
objectivesPlugin.objectives[Objectives.AUTOSENS_OBJECTIVE].startedOn = 0
|
||||
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_openapsama_use_autosens, false)).thenReturn(false)
|
||||
val c = constraintChecker.isAutosensModeEnabled()
|
||||
Assert.assertEquals(true, c.reasonList.size == 2) // Safety & Objectives
|
||||
Assert.assertEquals(true, c.mostLimitedReasonList.size == 2) // Safety & Objectives
|
||||
Assert.assertEquals(java.lang.Boolean.FALSE, c.value())
|
||||
Assertions.assertEquals(true, c.reasonList.size == 2) // Safety & Objectives
|
||||
Assertions.assertEquals(true, c.mostLimitedReasonList.size == 2) // Safety & Objectives
|
||||
Assertions.assertEquals(java.lang.Boolean.FALSE, c.value())
|
||||
}
|
||||
|
||||
// Safety
|
||||
|
@ -296,9 +304,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
fun isAdvancedFilteringEnabledTest() {
|
||||
`when`(activePlugin.activeBgSource).thenReturn(glimpPlugin)
|
||||
val c = constraintChecker.isAdvancedFilteringEnabled()
|
||||
Assert.assertEquals(true, c.reasonList.size == 1) // Safety
|
||||
Assert.assertEquals(true, c.mostLimitedReasonList.size == 1) // Safety
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertEquals(true, c.reasonList.size == 1) // Safety
|
||||
Assertions.assertEquals(true, c.mostLimitedReasonList.size == 1) // Safety
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
// SMB should limit
|
||||
|
@ -306,7 +314,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
fun isSuperBolusEnabledTest() {
|
||||
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
|
||||
val c = constraintChecker.isSuperBolusEnabled()
|
||||
Assert.assertEquals(java.lang.Boolean.FALSE, c.value()) // SMB should limit
|
||||
Assertions.assertEquals(java.lang.Boolean.FALSE, c.value()) // SMB should limit
|
||||
}
|
||||
|
||||
// Safety & Objectives
|
||||
|
@ -318,9 +326,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("open")
|
||||
// `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(Constraint(true))
|
||||
val c = constraintChecker.isSMBModeEnabled()
|
||||
Assert.assertEquals(true, c.reasonList.size == 3) // 2x Safety & Objectives
|
||||
Assert.assertEquals(true, c.mostLimitedReasonList.size == 3) // 2x Safety & Objectives
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertEquals(true, c.reasonList.size == 3) // 2x Safety & Objectives
|
||||
Assertions.assertEquals(true, c.mostLimitedReasonList.size == 3) // 2x Safety & Objectives
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
// applyBasalConstraints tests
|
||||
|
@ -346,9 +354,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val d = constraintChecker.getMaxBasalAllowed(validProfile)
|
||||
Assert.assertEquals(0.8, d.value(), 0.01)
|
||||
Assert.assertEquals(3, d.reasonList.size)
|
||||
Assert.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(0.8, d.value(), 0.01)
|
||||
Assertions.assertEquals(3, d.reasonList.size)
|
||||
Assertions.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -373,9 +381,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val i = constraintChecker.getMaxBasalPercentAllowed(validProfile)
|
||||
Assert.assertEquals(200, i.value())
|
||||
Assert.assertEquals(6, i.reasonList.size)
|
||||
Assert.assertEquals("Safety: Limiting max percent rate to 200% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(200, i.value())
|
||||
Assertions.assertEquals(6, i.reasonList.size)
|
||||
Assertions.assertEquals("Safety: Limiting max percent rate to 200% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
// applyBolusConstraints tests
|
||||
|
@ -400,9 +408,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val d = constraintChecker.getMaxBolusAllowed()
|
||||
Assert.assertEquals(3.0, d.value(), 0.01)
|
||||
Assert.assertEquals(4, d.reasonList.size) // 2x Safety & RS & R
|
||||
Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(3.0, d.value(), 0.01)
|
||||
Assertions.assertEquals(4, d.reasonList.size) // 2x Safety & RS & R
|
||||
Assertions.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
// applyCarbsConstraints tests
|
||||
|
@ -413,9 +421,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val i = constraintChecker.getMaxCarbsAllowed()
|
||||
Assert.assertEquals(48, i.value())
|
||||
Assert.assertEquals(true, i.reasonList.size == 1)
|
||||
Assert.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(48, i.value())
|
||||
Assertions.assertEquals(true, i.reasonList.size == 1)
|
||||
Assertions.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
// applyMaxIOBConstraints tests
|
||||
|
@ -430,9 +438,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val d = constraintChecker.getMaxIOBAllowed()
|
||||
Assert.assertEquals(1.5, d.value(), 0.01)
|
||||
Assert.assertEquals(d.reasonList.toString(), 2, d.reasonList.size)
|
||||
Assert.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(1.5, d.value(), 0.01)
|
||||
Assertions.assertEquals(2, d.reasonList.size)
|
||||
Assertions.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -446,8 +454,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
|
||||
// Apply all limits
|
||||
val d = constraintChecker.getMaxIOBAllowed()
|
||||
Assert.assertEquals(3.0, d.value(), 0.01)
|
||||
Assert.assertEquals(d.reasonList.toString(), 2, d.reasonList.size)
|
||||
Assert.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(3.0, d.value(), 0.01)
|
||||
Assertions.assertEquals(2, d.reasonList.size)
|
||||
Assertions.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
}
|
|
@ -4,12 +4,13 @@ import dagger.android.AndroidInjector
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.HardLimitsMock
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.interfaces.ApsMode
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
import info.nightscout.interfaces.profiling.Profiler
|
||||
|
@ -22,7 +23,7 @@ import info.nightscout.plugins.constraints.safety.SafetyPlugin
|
|||
import info.nightscout.plugins.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.plugins.source.GlimpPlugin
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
|
@ -38,6 +39,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
@Mock lateinit var profiler: Profiler
|
||||
@Mock lateinit var repository: AppRepository
|
||||
@Mock lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||
@Mock lateinit var bgQualityCheck: BgQualityCheck
|
||||
|
||||
private lateinit var hardLimits: HardLimits
|
||||
private lateinit var safetyPlugin: SafetyPlugin
|
||||
|
@ -81,7 +83,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
)
|
||||
openAPSSMBPlugin = OpenAPSSMBPlugin(
|
||||
injector, aapsLogger, rxBus, constraintChecker, rh, profileFunction, context, activePlugin, iobCobCalculator, hardLimits, profiler, sp,
|
||||
dateUtil, repository, glucoseStatusProvider
|
||||
dateUtil, repository, glucoseStatusProvider, bgQualityCheck
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -90,8 +92,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
pumpDescription.isTempBasalCapable = false
|
||||
var c = Constraint(true)
|
||||
c = safetyPlugin.isLoopInvocationAllowed(c)
|
||||
Assert.assertEquals("Safety: Pump is not temp basal capable", c.getReasons(aapsLogger))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertEquals("Safety: Pump is not temp basal capable", c.getReasons(aapsLogger))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -100,8 +102,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(config.isEngineeringModeOrRelease()).thenReturn(false)
|
||||
var c = Constraint(true)
|
||||
c = safetyPlugin.isClosedLoopAllowed(c)
|
||||
Assert.assertTrue(c.getReasons(aapsLogger).contains("Running dev version. Closed loop is disabled."))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertTrue(c.getReasons(aapsLogger).contains("Running dev version. Closed loop is disabled."))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -109,8 +111,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.lowercase)).thenReturn(ApsMode.OPEN.lowercase)
|
||||
var c = Constraint(true)
|
||||
c = safetyPlugin.isClosedLoopAllowed(c)
|
||||
Assert.assertTrue(c.getReasons(aapsLogger).contains("Closed loop mode disabled in preferences"))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertTrue(c.getReasons(aapsLogger).contains("Closed loop mode disabled in preferences"))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -119,8 +121,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(true))
|
||||
var c = Constraint(true)
|
||||
c = openAPSSMBPlugin.isSMBModeEnabled(c)
|
||||
Assert.assertTrue(c.getReasons(aapsLogger).contains("SMB disabled in preferences"))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertTrue(c.getReasons(aapsLogger).contains("SMB disabled in preferences"))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -129,8 +131,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(false))
|
||||
var c = Constraint(true)
|
||||
c = safetyPlugin.isSMBModeEnabled(c)
|
||||
Assert.assertTrue(c.getReasons(aapsLogger).contains("SMB not allowed in open loop mode"))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertTrue(c.getReasons(aapsLogger).contains("SMB not allowed in open loop mode"))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -138,8 +140,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(activePlugin.activeBgSource).thenReturn(glimpPlugin)
|
||||
var c = Constraint(true)
|
||||
c = safetyPlugin.isAdvancedFilteringEnabled(c)
|
||||
Assert.assertEquals("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering", c.getReasons(aapsLogger))
|
||||
Assert.assertEquals(false, c.value())
|
||||
Assertions.assertEquals("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering", c.getReasons(aapsLogger))
|
||||
Assertions.assertEquals(false, c.value())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -150,13 +152,13 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
val c = Constraint(Constants.REALLYHIGHBASALRATE)
|
||||
safetyPlugin.applyBasalConstraints(c, validProfile)
|
||||
Assert.assertEquals(2.0, c.value(), 0.01)
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(2.0, c.value(), 0.01)
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Safety: Limiting max basal rate to 2.00 U/h because of hard limit
|
||||
""".trimIndent(), c.getReasons(aapsLogger)
|
||||
)
|
||||
Assert.assertEquals("Safety: Limiting max basal rate to 2.00 U/h because of hard limit", c.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting max basal rate to 2.00 U/h because of hard limit", c.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -164,8 +166,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
val d = Constraint(-0.5)
|
||||
safetyPlugin.applyBasalConstraints(d, validProfile)
|
||||
Assert.assertEquals(0.0, d.value(), 0.01)
|
||||
Assert.assertEquals("Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value", d.getReasons(aapsLogger))
|
||||
Assertions.assertEquals(0.0, d.value(), 0.01)
|
||||
Assertions.assertEquals("Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value", d.getReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -177,8 +179,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
val i = Constraint(Constants.REALLYHIGHPERCENTBASALRATE)
|
||||
safetyPlugin.applyBasalPercentConstraints(i, validProfile)
|
||||
Assert.assertEquals(200, i.value())
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(200, i.value())
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Safety: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h
|
||||
Safety: Limiting max basal rate to 2.00 U/h because of hard limit
|
||||
|
@ -186,7 +188,7 @@ Safety: Limiting max percent rate to 200% because of pump limit
|
|||
Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
||||
""".trimIndent(), i.getReasons(aapsLogger)
|
||||
)
|
||||
Assert.assertEquals("Safety: Limiting max percent rate to 200% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting max percent rate to 200% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -199,15 +201,15 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
|
||||
val i = Constraint(Constants.REALLYHIGHBASALRATE)
|
||||
openAPSSMBPlugin.applyBasalConstraints(i, validProfile)
|
||||
Assert.assertEquals(1.0, i.value(), 0.01)
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(1.0, i.value(), 0.01)
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences
|
||||
OpenAPSSMB: Limiting max basal rate to 4.00 U/h because of max basal multiplier
|
||||
OpenAPSSMB: Limiting max basal rate to 3.00 U/h because of max daily basal multiplier
|
||||
""".trimIndent(), i.getReasons(aapsLogger)
|
||||
)
|
||||
Assert.assertEquals("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences", i.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences", i.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -215,15 +217,15 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
val i = Constraint(-22)
|
||||
safetyPlugin.applyBasalPercentConstraints(i, validProfile)
|
||||
Assert.assertEquals(0, i.value())
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(0, i.value())
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Safety: Percent rate -22% recalculated to -0.22 U/h with current basal 1.00 U/h
|
||||
Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value
|
||||
Safety: Limiting max percent rate to 0% because of pump limit
|
||||
""".trimIndent(), i.getReasons(aapsLogger)
|
||||
)
|
||||
Assert.assertEquals("Safety: Limiting max percent rate to 0% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting max percent rate to 0% because of pump limit", i.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -232,14 +234,14 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
var d = Constraint(Constants.REALLYHIGHBOLUS)
|
||||
d = safetyPlugin.applyBolusConstraints(d)
|
||||
Assert.assertEquals(3.0, d.value(), 0.01)
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(3.0, d.value(), 0.01)
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Safety: Limiting bolus to 3.0 U because of max value in preferences
|
||||
Safety: Limiting bolus to 5.0 U because of hard limit
|
||||
""".trimIndent(), d.getReasons(aapsLogger)
|
||||
)
|
||||
Assert.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting bolus to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -248,9 +250,9 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
|
||||
var d = Constraint(-22.0)
|
||||
d = safetyPlugin.applyBolusConstraints(d)
|
||||
Assert.assertEquals(0.0, d.value(), 0.01)
|
||||
Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getReasons(aapsLogger))
|
||||
Assert.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(0.0, d.value(), 0.01)
|
||||
Assertions.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting bolus to 0.0 U because of it must be positive value", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -261,13 +263,13 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
// Negative carbs not allowed
|
||||
var i = Constraint(-22)
|
||||
safetyPlugin.applyCarbsConstraints(i)
|
||||
Assert.assertEquals(0, i.value())
|
||||
Assert.assertEquals("Safety: Limiting carbs to 0 g because of it must be positive value", i.getReasons(aapsLogger))
|
||||
Assertions.assertEquals(0, i.value())
|
||||
Assertions.assertEquals("Safety: Limiting carbs to 0 g because of it must be positive value", i.getReasons(aapsLogger))
|
||||
|
||||
// Apply all limits
|
||||
i = safetyPlugin.applyCarbsConstraints(Constraint(Constants.REALLYHIGHCARBS))
|
||||
Assert.assertEquals(48, i.value())
|
||||
Assert.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getReasons(aapsLogger))
|
||||
Assertions.assertEquals(48, i.value())
|
||||
Assertions.assertEquals("Safety: Limiting carbs to 48 g because of max value in preferences", i.getReasons(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -284,22 +286,22 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
|
|||
// Apply all limits
|
||||
var d = Constraint(Constants.REALLYHIGHIOB)
|
||||
d = safetyPlugin.applyMaxIOBConstraints(d)
|
||||
Assert.assertEquals(HardLimits.MAX_IOB_LGS, d.value(), 0.01)
|
||||
Assert.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getReasons(aapsLogger))
|
||||
Assert.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(HardLimits.MAX_IOB_LGS, d.value(), 0.01)
|
||||
Assertions.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getReasons(aapsLogger))
|
||||
Assertions.assertEquals("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend", d.getMostLimitedReasons(aapsLogger))
|
||||
|
||||
// Apply all limits
|
||||
d = Constraint(Constants.REALLYHIGHIOB)
|
||||
val a = openAPSAMAPlugin.applyMaxIOBConstraints(d)
|
||||
Assert.assertEquals(1.5, a.value(), 0.01)
|
||||
Assert.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences\nOpenAPSAMA: Limiting IOB to 7.0 U because of hard limit", d.getReasons(aapsLogger))
|
||||
Assert.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(1.5, a.value(), 0.01)
|
||||
Assertions.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences\nOpenAPSAMA: Limiting IOB to 7.0 U because of hard limit", d.getReasons(aapsLogger))
|
||||
Assertions.assertEquals("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
|
||||
// Apply all limits
|
||||
d = Constraint(Constants.REALLYHIGHIOB)
|
||||
val s = openAPSSMBPlugin.applyMaxIOBConstraints(d)
|
||||
Assert.assertEquals(3.0, s.value(), 0.01)
|
||||
Assert.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences\nOpenAPSSMB: Limiting IOB to 22.0 U because of hard limit", d.getReasons(aapsLogger))
|
||||
Assert.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
Assertions.assertEquals(3.0, s.value(), 0.01)
|
||||
Assertions.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences\nOpenAPSSMB: Limiting IOB to 22.0 U because of hard limit", d.getReasons(aapsLogger))
|
||||
Assertions.assertEquals("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences", d.getMostLimitedReasons(aapsLogger))
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import info.nightscout.plugins.aps.loop.extensions.json
|
|||
import info.nightscout.plugins.extensions.toText
|
||||
import info.nightscout.plugins.sync.nsShared.extensions.log
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito.`when`
|
||||
|
@ -43,91 +43,84 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.success(true)
|
||||
Assert.assertEquals(true, per.success)
|
||||
Assertions.assertEquals(true, per.success)
|
||||
}
|
||||
|
||||
@Test fun enactedTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.enacted(true)
|
||||
Assert.assertEquals(true, per.enacted)
|
||||
Assertions.assertEquals(true, per.enacted)
|
||||
}
|
||||
|
||||
@Test fun commentTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.comment("SomeComment")
|
||||
Assert.assertEquals("SomeComment", per.comment)
|
||||
Assertions.assertEquals("SomeComment", per.comment)
|
||||
}
|
||||
|
||||
@Test fun durationTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.duration(10)
|
||||
Assert.assertEquals(10, per.duration.toLong())
|
||||
Assertions.assertEquals(10, per.duration.toLong())
|
||||
}
|
||||
|
||||
@Test fun absoluteTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.absolute(11.0)
|
||||
Assert.assertEquals(11.0, per.absolute, 0.01)
|
||||
Assertions.assertEquals(11.0, per.absolute, 0.01)
|
||||
}
|
||||
|
||||
@Test fun percentTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.percent(10)
|
||||
Assert.assertEquals(10, per.percent)
|
||||
Assertions.assertEquals(10, per.percent)
|
||||
}
|
||||
|
||||
@Test fun isPercentTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.isPercent(true)
|
||||
Assert.assertEquals(true, per.isPercent)
|
||||
Assertions.assertEquals(true, per.isPercent)
|
||||
}
|
||||
|
||||
@Test fun isTempCancelTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.isTempCancel(true)
|
||||
Assert.assertEquals(true, per.isTempCancel)
|
||||
Assertions.assertEquals(true, per.isTempCancel)
|
||||
}
|
||||
|
||||
@Test fun bolusDeliveredTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.bolusDelivered(11.0)
|
||||
Assert.assertEquals(11.0, per.bolusDelivered, 0.01)
|
||||
}
|
||||
|
||||
@Test fun carbsDeliveredTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.carbsDelivered(11.0)
|
||||
Assert.assertEquals(11.0, per.carbsDelivered, 0.01)
|
||||
Assertions.assertEquals(11.0, per.bolusDelivered, 0.01)
|
||||
}
|
||||
|
||||
@Test fun queuedTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
per.queued(true)
|
||||
Assert.assertEquals(true, per.queued)
|
||||
Assertions.assertEquals(true, per.queued)
|
||||
}
|
||||
|
||||
@Test fun logTest() {
|
||||
val per = PumpEnactResult(injector)
|
||||
|
||||
Assert.assertEquals(
|
||||
"Success: false Enacted: false Comment: Duration: -1 Absolute: -1.0 Percent: -1 IsPercent: false IsTempCancel: false bolusDelivered: 0.0 carbsDelivered: 0.0 Queued: false",
|
||||
Assertions.assertEquals(
|
||||
"Success: false Enacted: false Comment: Duration: -1 Absolute: -1.0 Percent: -1 IsPercent: false IsTempCancel: false bolusDelivered: 0.0 Queued: false",
|
||||
per.log()
|
||||
)
|
||||
}
|
||||
|
||||
@Test fun toStringTest() {
|
||||
var per = PumpEnactResult(injector).enacted(true).bolusDelivered(10.0).comment("AAA")
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Success: false
|
||||
Enacted: true
|
||||
|
@ -136,7 +129,7 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
""".trimIndent(), per.toText(rh)
|
||||
)
|
||||
per = PumpEnactResult(injector).enacted(true).isTempCancel(true).comment("AAA")
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Success: false
|
||||
Enacted: true
|
||||
|
@ -145,7 +138,7 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
""".trimIndent(), per.toText(rh)
|
||||
)
|
||||
per = PumpEnactResult(injector).enacted(true).isPercent(true).percent(90).duration(20).comment("AAA")
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Success: false
|
||||
Enacted: true
|
||||
|
@ -155,7 +148,7 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
""".trimIndent(), per.toText(rh)
|
||||
)
|
||||
per = PumpEnactResult(injector).enacted(true).isPercent(false).absolute(1.0).duration(30).comment("AAA")
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Success: false
|
||||
Enacted: true
|
||||
|
@ -165,7 +158,7 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
""".trimIndent(), per.toText(rh)
|
||||
)
|
||||
per = PumpEnactResult(injector).enacted(false).comment("AAA")
|
||||
Assert.assertEquals(
|
||||
Assertions.assertEquals(
|
||||
"""
|
||||
Success: false
|
||||
Comment: AAA
|
||||
|
@ -176,15 +169,15 @@ class PumpEnactResultTest : TestBaseWithProfile() {
|
|||
@Test fun toHtmlTest() {
|
||||
|
||||
var per: PumpEnactResult = PumpEnactResult(injector).enacted(true).bolusDelivered(10.0).comment("AAA")
|
||||
Assert.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>SMB</b>: 10.0 U", per.toHtml(rh))
|
||||
Assertions.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>SMB</b>: 10.0 U", per.toHtml(rh))
|
||||
per = PumpEnactResult(injector).enacted(true).isTempCancel(true).comment("AAA")
|
||||
Assert.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br>Cancel temp basal", per.toHtml(rh))
|
||||
Assertions.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br>Cancel temp basal", per.toHtml(rh))
|
||||
per = PumpEnactResult(injector).enacted(true).isPercent(true).percent(90).duration(20).comment("AAA")
|
||||
Assert.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>Duration</b>: 20 min<br><b>Percent</b>: 90%", per.toHtml(rh))
|
||||
Assertions.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>Duration</b>: 20 min<br><b>Percent</b>: 90%", per.toHtml(rh))
|
||||
per = PumpEnactResult(injector).enacted(true).isPercent(false).absolute(1.0).duration(30).comment("AAA")
|
||||
Assert.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>Duration</b>: 30 min<br><b>Absolute</b>: 1.00 U/h", per.toHtml(rh))
|
||||
Assertions.assertEquals("<b>Success</b>: false<br><b>Enacted</b>: true<br><b>Comment</b>: AAA<br><b>Duration</b>: 30 min<br><b>Absolute</b>: 1.00 U/h", per.toHtml(rh))
|
||||
per = PumpEnactResult(injector).enacted(false).comment("AAA")
|
||||
Assert.assertEquals("<b>Success</b>: false<br><b>Comment</b>: AAA", per.toHtml(rh))
|
||||
Assertions.assertEquals("<b>Success</b>: false<br><b>Comment</b>: AAA", per.toHtml(rh))
|
||||
}
|
||||
|
||||
@Test fun jsonTest() {
|
||||
|
|
|
@ -12,7 +12,7 @@ buildscript {
|
|||
dagger_version = '2.44.2'
|
||||
coroutines_version = '1.6.4'
|
||||
activity_version = '1.6.1'
|
||||
fragmentktx_version = '1.5.4'
|
||||
fragmentktx_version = '1.5.5'
|
||||
ormLite_version = '4.46'
|
||||
gson_version = '2.10'
|
||||
nav_version = '2.5.3'
|
||||
|
@ -32,7 +32,7 @@ buildscript {
|
|||
swipe_version = '1.1.0'
|
||||
|
||||
junit_version = '4.13.2'
|
||||
junit_jupiter_version = '5.7.0'
|
||||
junit_jupiter_version = '5.9.1'
|
||||
mockito_version = '4.6.1'
|
||||
dexmaker_version = '1.2'
|
||||
retrofit2_version = '2.9.0'
|
||||
|
|
|
@ -30,7 +30,7 @@ interface DetermineBasalAdapter {
|
|||
microBolusAllowed: Boolean = false,
|
||||
uamAllowed: Boolean = false,
|
||||
advancedFiltering: Boolean = false,
|
||||
isSaveCgmSource: Boolean = false
|
||||
flatBGsDetected: Boolean = false
|
||||
)
|
||||
|
||||
operator fun invoke(): APSResult?
|
||||
|
|
|
@ -3,6 +3,15 @@ package info.nightscout.interfaces.bgQualityCheck
|
|||
import androidx.annotation.DrawableRes
|
||||
|
||||
interface BgQualityCheck {
|
||||
enum class State {
|
||||
UNKNOWN,
|
||||
FIVE_MIN_DATA,
|
||||
RECALCULATED,
|
||||
DOUBLED,
|
||||
FLAT // stale data for 45 min
|
||||
}
|
||||
|
||||
var state: State
|
||||
var message: String
|
||||
@DrawableRes fun icon(): Int
|
||||
fun stateDescription(): String
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.interfaces.iob
|
||||
|
||||
interface GlucoseStatusProvider {
|
||||
val glucoseStatusData: GlucoseStatus?
|
||||
fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus?
|
||||
}
|
|
@ -25,7 +25,6 @@ class PumpEnactResult(injector: HasAndroidInjector) {
|
|||
|
||||
// Result of treatment delivery
|
||||
var bolusDelivered = 0.0 // real value of delivered insulin
|
||||
var carbsDelivered = 0.0 // real value of delivered carbs
|
||||
var queued = false
|
||||
|
||||
fun success(success: Boolean): PumpEnactResult = this.also { this.success = success }
|
||||
|
@ -38,6 +37,5 @@ class PumpEnactResult(injector: HasAndroidInjector) {
|
|||
fun isPercent(isPercent: Boolean): PumpEnactResult = this.also { it.isPercent = isPercent }
|
||||
fun isTempCancel(isTempCancel: Boolean): PumpEnactResult = this.also { it.isTempCancel = isTempCancel }
|
||||
fun bolusDelivered(bolusDelivered: Double): PumpEnactResult = this.also { it.bolusDelivered = bolusDelivered }
|
||||
fun carbsDelivered(carbsDelivered: Double): PumpEnactResult = this.also { it.carbsDelivered = carbsDelivered }
|
||||
fun queued(queued: Boolean): PumpEnactResult = this.also { it.queued = queued }
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package info.nightscout.interfaces.source
|
||||
|
||||
interface DexcomBoyda
|
|
@ -6,7 +6,6 @@ import com.google.common.base.Joiner
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.extensions.highValueToUnitsToString
|
||||
import info.nightscout.core.extensions.lowValueToUnitsToString
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.ui.dialogs.OKDialog
|
||||
import info.nightscout.core.utils.extensions.formatColor
|
||||
|
@ -24,6 +23,7 @@ import info.nightscout.interfaces.constraints.Constraint
|
|||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.db.PersistenceLayer
|
||||
import info.nightscout.interfaces.iob.GlucoseStatus
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
|
|
|
@ -3,13 +3,13 @@ package info.nightscout.core.wizard
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.extensions.valueToUnits
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.utils.MidnightUtils
|
||||
import info.nightscout.database.ValueWrapper
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.interfaces.aps.Loop
|
||||
import info.nightscout.interfaces.db.PersistenceLayer
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
package info.nightscout.androidaps
|
||||
|
||||
import androidx.collection.ArrayMap
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.extensions.pureProfileFromJson
|
||||
import info.nightscout.core.profile.ProfileSealed
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileStore
|
||||
import info.nightscout.interfaces.profile.PureProfile
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.interfaces.utils.JsonHelper
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
|
||||
class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JSONObject, val dateUtil: DateUtil) : ProfileStore {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var hardLimits: HardLimits
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
}
|
||||
|
||||
private val cachedObjects = ArrayMap<String, PureProfile>()
|
||||
|
||||
private fun storeUnits(): String? = JsonHelper.safeGetStringAllowNull(data, "units", null)
|
||||
|
||||
private fun getStore(): JSONObject? {
|
||||
try {
|
||||
if (data.has("store")) return data.getJSONObject("store")
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error("Unhandled exception", e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getStartDate(): Long {
|
||||
val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0
|
||||
return try {
|
||||
dateUtil.fromISODateString(iso)
|
||||
} catch (e: Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultProfile(): PureProfile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
|
||||
override fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) }
|
||||
|
||||
override fun getDefaultProfileName(): String? {
|
||||
val defaultProfileName = data.optString("defaultProfile")
|
||||
return if (defaultProfileName.isNotEmpty()) getStore()?.has(defaultProfileName)?.let { defaultProfileName } else null
|
||||
}
|
||||
|
||||
override fun getProfileList(): ArrayList<CharSequence> {
|
||||
val ret = ArrayList<CharSequence>()
|
||||
getStore()?.keys()?.let { keys ->
|
||||
while (keys.hasNext()) {
|
||||
val profileName = keys.next() as String
|
||||
ret.add(profileName)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun getSpecificProfile(profileName: String): PureProfile? {
|
||||
var profile: PureProfile? = null
|
||||
val units = JsonHelper.safeGetStringAllowNull(data, "units", storeUnits())
|
||||
getStore()?.let { store ->
|
||||
if (store.has(profileName)) {
|
||||
profile = cachedObjects[profileName]
|
||||
if (profile == null) {
|
||||
JsonHelper.safeGetJSONObject(store, profileName, null)?.let { profileObject ->
|
||||
profile = pureProfileFromJson(profileObject, dateUtil, units)
|
||||
profile?.let { cachedObjects[profileName] = profile }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return profile
|
||||
}
|
||||
|
||||
private fun getSpecificProfileJson(profileName: String): JSONObject? {
|
||||
getStore()?.let { store ->
|
||||
if (store.has(profileName))
|
||||
return JsonHelper.safeGetJSONObject(store, profileName, null)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override val allProfilesValid: Boolean
|
||||
get() = getProfileList()
|
||||
.asSequence()
|
||||
.map { profileName -> getSpecificProfile(profileName.toString()) }
|
||||
.map { pureProfile -> pureProfile?.let { ProfileSealed.Pure(pureProfile).isValid("allProfilesValid", activePlugin.activePump, config, rh, rxBus, hardLimits, false) } }
|
||||
.all { it?.isValid == true }
|
||||
}
|
|
@ -10,7 +10,6 @@ import info.nightscout.interfaces.plugin.ActivePlugin
|
|||
import info.nightscout.interfaces.profile.DefaultValueHelper
|
||||
import info.nightscout.interfaces.profile.Profile
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.profile.ProfileStore
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
|
@ -38,18 +37,7 @@ open class TestBaseWithProfile : TestBase() {
|
|||
|
||||
val rxBus = RxBus(aapsSchedulers, aapsLogger)
|
||||
|
||||
val profileInjector = HasAndroidInjector {
|
||||
AndroidInjector {
|
||||
if (it is ProfileStoreObject) {
|
||||
it.aapsLogger = aapsLogger
|
||||
it.activePlugin = activePluginProvider
|
||||
it.config = config
|
||||
it.rh = rh
|
||||
it.rxBus = rxBus
|
||||
it.hardLimits = hardLimits
|
||||
}
|
||||
}
|
||||
}
|
||||
val profileInjector = HasAndroidInjector { AndroidInjector { } }
|
||||
|
||||
private lateinit var invalidProfileJSON: String
|
||||
private lateinit var validProfileJSON: String
|
||||
|
@ -70,32 +58,4 @@ open class TestBaseWithProfile : TestBase() {
|
|||
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
||||
hardLimits = HardLimitsMock(sp, rh)
|
||||
}
|
||||
|
||||
fun getValidProfileStore(): ProfileStore {
|
||||
val json = JSONObject()
|
||||
val store = JSONObject()
|
||||
store.put(TESTPROFILENAME, JSONObject(validProfileJSON))
|
||||
json.put("defaultProfile", TESTPROFILENAME)
|
||||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
|
||||
fun getInvalidProfileStore1(): ProfileStore {
|
||||
val json = JSONObject()
|
||||
val store = JSONObject()
|
||||
store.put(TESTPROFILENAME, JSONObject(invalidProfileJSON))
|
||||
json.put("defaultProfile", TESTPROFILENAME)
|
||||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
|
||||
fun getInvalidProfileStore2(): ProfileStore {
|
||||
val json = JSONObject()
|
||||
val store = JSONObject()
|
||||
store.put(TESTPROFILENAME, JSONObject(validProfileJSON))
|
||||
store.put("invalid", JSONObject(invalidProfileJSON))
|
||||
json.put("defaultProfile", TESTPROFILENAME + "invalid")
|
||||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,316 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator
|
||||
|
||||
import android.content.Context
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.core.iob.iobCobCalculator.AutosensDataStoreObject
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import info.nightscout.shared.utils.T
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
|
||||
class AutosensDataStoreTest : TestBase() {
|
||||
|
||||
@Mock lateinit var context: Context
|
||||
|
||||
lateinit var dateUtil: DateUtil
|
||||
|
||||
private val autosensDataStore = AutosensDataStoreObject()
|
||||
|
||||
@BeforeEach
|
||||
fun mock() {
|
||||
dateUtil = DateUtil(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isAbout5minDataTest() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
|
||||
// Super data should not be touched
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
|
||||
// too much shifted data should return false
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
|
||||
// too much shifted and missing data should return false
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
|
||||
// too much shifted and missing data should return false
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(83).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(78).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(73).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(68).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(63).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(58).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(53).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(48).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(43).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(38).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(33).plus(T.secs(1)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(28).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(23).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(16).plus(T.secs(36)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
|
||||
// slightly shifted data should return true
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
|
||||
// slightly shifted and missing data should return true
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createBucketedData5minTest1() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
|
||||
// Super data should not be touched
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(bgReadingList[0].timestamp, autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(bgReadingList[3].timestamp, autosensDataStore.bucketedData!![3].timestamp)
|
||||
Assert.assertEquals(bgReadingList.size.toLong(), autosensDataStore.bucketedData!!.size.toLong())
|
||||
|
||||
// Missing value should be replaced
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(bgReadingList[0].timestamp, autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(bgReadingList[2].timestamp, autosensDataStore.bucketedData!![3].timestamp)
|
||||
Assert.assertEquals(bgReadingList.size + 1.toLong(), autosensDataStore.bucketedData!!.size.toLong())
|
||||
|
||||
// drift should be cleared
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(T.mins(15).msecs(), autosensDataStore.bucketedData!![1].timestamp)
|
||||
Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.bucketedData!![2].timestamp)
|
||||
Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.bucketedData!![3].timestamp)
|
||||
Assert.assertEquals(bgReadingList.size.toLong(), autosensDataStore.bucketedData!!.size.toLong())
|
||||
|
||||
// bucketed data should return null if not enough bg data
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(30).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(null, autosensDataStore.bucketedData)
|
||||
|
||||
// data should be reconstructed
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 90.0, timestamp = T.mins(45).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(T.mins(50).msecs(), autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![6].timestamp)
|
||||
Assert.assertEquals(7, autosensDataStore.bucketedData!!.size.toLong())
|
||||
Assert.assertEquals(100.0, autosensDataStore.bucketedData!![0].value, 1.0)
|
||||
Assert.assertEquals(90.0, autosensDataStore.bucketedData!![1].value, 1.0)
|
||||
Assert.assertEquals(50.0, autosensDataStore.bucketedData!![5].value, 1.0)
|
||||
Assert.assertEquals(40.0, autosensDataStore.bucketedData!![6].value, 1.0)
|
||||
|
||||
// non 5min data should be reconstructed
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 96.0, timestamp = T.mins(48).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(T.mins(50).msecs(), autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.bucketedData!![6].timestamp)
|
||||
Assert.assertEquals(7, autosensDataStore.bucketedData!!.size.toLong())
|
||||
Assert.assertEquals(100.0, autosensDataStore.bucketedData!![0].value, 1.0)
|
||||
Assert.assertEquals(90.0, autosensDataStore.bucketedData!![1].value, 1.0)
|
||||
Assert.assertEquals(50.0, autosensDataStore.bucketedData!![5].value, 1.0)
|
||||
Assert.assertEquals(40.0, autosensDataStore.bucketedData!![6].value, 1.0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createBucketedData5minTest2() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
|
||||
//bucketed data should be null if no bg data available
|
||||
autosensDataStore.bgReadings = ArrayList()
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(null, autosensDataStore.bucketedData)
|
||||
|
||||
// real data gap test
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:34:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:14:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:09:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T13:04:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:59:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:54:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:49:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:44:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:39:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:34:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:29:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:24:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:19:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:14:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:09:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T12:04:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T11:59:55Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:29:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:24:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:19:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:14:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:10:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T04:04:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:59:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:54:56Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:50:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-09-05T03:44:57Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
autosensDataStore.referenceTime = -1
|
||||
Assert.assertEquals(true, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(dateUtil.fromISODateString("2018-09-05T13:34:57Z"), autosensDataStore.bucketedData!![0].timestamp)
|
||||
Assert.assertEquals(dateUtil.fromISODateString("2018-09-05T03:44:57Z"), autosensDataStore.bucketedData!![autosensDataStore.bucketedData!!.size - 1].timestamp)
|
||||
|
||||
// 5min 4sec data
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:33:40Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:28:36Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:23:32Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:18:28Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:13:24Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:08:19Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T06:03:16Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:58:11Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:53:07Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:48:03Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:42:58Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:37:54Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:32:51Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:27:46Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:22:42Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:17:38Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:12:33Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:07:29Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T05:02:26Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T04:57:21Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = dateUtil.fromISODateString("2018-10-05T04:52:17Z"), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(false, autosensDataStore.isAbout5minData(aapsLogger))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bgReadingsTest() {
|
||||
val bgReadingList: List<GlucoseValue> = ArrayList()
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
Assert.assertEquals(bgReadingList, autosensDataStore.bgReadings)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun roundUpTimeTest() {
|
||||
Assert.assertEquals(T.mins(3).msecs(), autosensDataStore.roundUpTime(T.secs(155).msecs()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findNewerTest() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findNewer(T.mins(8).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findNewer(T.mins(5).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findNewer(T.mins(10).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findNewer(T.mins(20).msecs())!!.timestamp)
|
||||
Assert.assertEquals(null, autosensDataStore.findNewer(T.mins(22).msecs()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findOlderTest() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findOlder(T.mins(8).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findOlder(T.mins(5).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(10).msecs(), autosensDataStore.findOlder(T.mins(10).msecs())!!.timestamp)
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findOlder(T.mins(20).msecs())!!.timestamp)
|
||||
Assert.assertEquals(null, autosensDataStore.findOlder(T.mins(4).msecs()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findPreviousTimeFromBucketedDataTest() {
|
||||
val bgReadingList: MutableList<GlucoseValue> = ArrayList()
|
||||
autosensDataStore.bgReadings = bgReadingList
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(null, autosensDataStore.findPreviousTimeFromBucketedData(1000))
|
||||
|
||||
// Super data should not be touched
|
||||
bgReadingList.clear()
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
bgReadingList.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 = bgReadingList
|
||||
autosensDataStore.createBucketedData(aapsLogger, dateUtil)
|
||||
Assert.assertEquals(null, autosensDataStore.findPreviousTimeFromBucketedData(T.mins(4).msecs()))
|
||||
Assert.assertEquals(T.mins(5).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(6).msecs()))
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(20).msecs()))
|
||||
Assert.assertEquals(T.mins(20).msecs(), autosensDataStore.findPreviousTimeFromBucketedData(T.mins(25).msecs()))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.core.ui.elements
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.SeekBarPreference
|
||||
|
||||
/**
|
||||
* Variant of SeekBarPreference with built-in string->int conversion.
|
||||
*
|
||||
* The normal SeekBarPreference crashes if the associated value in the
|
||||
* SharedPreferences is not an int. This is a problem, because AAPS
|
||||
* exports all settings as strings. When importing settings again,
|
||||
* the former int value becomes a string value as a consequence.
|
||||
*
|
||||
* For this reason, this variant exists. It tries to first read the
|
||||
* initial preference value from the preferences as an int. If it is
|
||||
* not an int, ClassCastException is thrown. This is caught, and the
|
||||
* value is re-read as a string and then converted to an int.
|
||||
*
|
||||
* To use this in fragment XMLs, replace "SeekBarPreference" in them
|
||||
* with "info.nightscout.core.ui.elements.IntSeekBarPreference".
|
||||
*/
|
||||
class IntSeekBarPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : SeekBarPreference(context, attrs) {
|
||||
override fun onSetInitialValue(defaultValue: Any?) {
|
||||
val actualDefaultValue = if (defaultValue == null)
|
||||
0
|
||||
else
|
||||
(defaultValue as Int?) ?: 0
|
||||
|
||||
val storedValue = try {
|
||||
getPersistedInt(actualDefaultValue)
|
||||
} catch (_: ClassCastException) {
|
||||
val keyToDelete = key
|
||||
// Remove the key manually. The setValue() function that is
|
||||
// used in the "value" property assignment below tries to look
|
||||
// up the existing stored value if it exists. If it does exist,
|
||||
// it tries to read the value - as an int. We then get another
|
||||
// ClassCastException. To avoid that, first delete the existing
|
||||
// value. This prevents setValue() from doing that int lookup.
|
||||
sharedPreferences?.edit {
|
||||
remove(keyToDelete)
|
||||
}
|
||||
getPersistedString(actualDefaultValue.toString()).toInt()
|
||||
}
|
||||
|
||||
value = storedValue
|
||||
}
|
||||
}
|
|
@ -162,6 +162,8 @@
|
|||
<string name="dia">DIA</string>
|
||||
<string name="ic_short">I:C</string>
|
||||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Rušení dočasného bazálu selhalo</string>
|
||||
<string name="canceling_eb_failed">Zastavení prodlouženého bolusu selhalo</string>
|
||||
<!-- Protection-->
|
||||
<string name="wrongpassword">Chybné heslo</string>
|
||||
<string name="wrongpin">Nesprávný PIN</string>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<string name="pump_base_basal_rate">%1$.2f U/h</string>
|
||||
<string name="pump_not_initialized_profile_not_set">Bomba no inicializada, ¡perfil no establecido!</string>
|
||||
<string name="failed_update_basal_profile">Error al actualizar el perfil basal</string>
|
||||
<string name="bolus_delivered_successfully">Bolo %1$.2fU entregado correctamente</string>
|
||||
<string name="no_valid_basal_rate">Tasa basal no válida leída en la bomba</string>
|
||||
<string name="limiting_iob">Limitando IOB a %1$.1f U debido a %2$s</string>
|
||||
<string name="loop_disabled">LAZO DESACTIVADO POR RESTRICCIONES</string>
|
||||
|
@ -161,6 +162,8 @@
|
|||
<string name="dia">DIA</string>
|
||||
<string name="ic_short">IC</string>
|
||||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Error cancelando la basal temporal</string>
|
||||
<string name="canceling_eb_failed">Error cancelando el bolo extendido</string>
|
||||
<!-- Protection-->
|
||||
<string name="wrongpassword">Contraseña incorrecta</string>
|
||||
<string name="wrongpin">Pin erróneo</string>
|
||||
|
@ -243,6 +246,7 @@
|
|||
<!-- CarbsReq-->
|
||||
<string name="carbsreq">%1$d g carbohidratos adicionales necesarios en %2$d minutos</string>
|
||||
<!-- TDDStatsActivity-->
|
||||
<string name="cumulative_tdd">TDD acumulativa</string>
|
||||
<string name="expweight">TDD ampliada exponencialmente</string>
|
||||
<string name="basalrate">Dosis Basal</string>
|
||||
<string name="bolus">Bolo</string>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<string name="pump_base_basal_rate">%1$.2f E/t</string>
|
||||
<string name="pump_not_initialized_profile_not_set">Pumpen ikke initialisert, ingen profil valgt!</string>
|
||||
<string name="failed_update_basal_profile">Klarte ikke å oppdatere basalprofil</string>
|
||||
<string name="bolus_delivered_successfully">Bolus %1$.2f E ble levert vellykket</string>
|
||||
<string name="no_valid_basal_rate">Ingen gyldige basaldoser ble lest fra pumpen</string>
|
||||
<string name="limiting_iob">Begrenser IOB til %1$.1f E på grunn av %2$s</string>
|
||||
<string name="loop_disabled">LOOP DEAKTIVERT PGA BEGRENSNINGER</string>
|
||||
|
@ -105,6 +106,7 @@
|
|||
<string name="loading">Laster…</string>
|
||||
<string name="notes_label">Merknader</string>
|
||||
<string name="remove_button">Fjern</string>
|
||||
<string name="add_new">Legg til ny</string>
|
||||
<string name="addnew_above">Legg til ny over</string>
|
||||
<string name="wrong_pump_data">Data kommer fra forskjellige pumper. Bytt pumpevalg for å nullstille pumpens tilstand.</string>
|
||||
<string name="bg_label">BS</string>
|
||||
|
@ -160,6 +162,8 @@
|
|||
<string name="dia">DIA</string>
|
||||
<string name="ic_short">IK</string>
|
||||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Kansellering av Temp Basal feilet</string>
|
||||
<string name="canceling_eb_failed">Kansellering av forlenget bolus feilet</string>
|
||||
<!-- Protection-->
|
||||
<string name="wrongpassword">Feil passord</string>
|
||||
<string name="wrongpin">Feil PIN-kode</string>
|
||||
|
@ -242,6 +246,7 @@
|
|||
<!-- CarbsReq-->
|
||||
<string name="carbsreq">%1$d g ekstra karbohydrater kreves innen %2$d minutter</string>
|
||||
<!-- TDDStatsActivity-->
|
||||
<string name="cumulative_tdd">Akkumulert TDD</string>
|
||||
<string name="expweight">Eksponentielt vektet TDD</string>
|
||||
<string name="basalrate">Basal</string>
|
||||
<string name="bolus">Bolus</string>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<string name="pump_base_basal_rate">%1$.2f ед/ч</string>
|
||||
<string name="pump_not_initialized_profile_not_set">помпа не инициализирована, профиль не установлен</string>
|
||||
<string name="failed_update_basal_profile">не удалось обновить базальный профиль</string>
|
||||
<string name="bolus_delivered_successfully">Болюс %1$.2f ед. подан успешно</string>
|
||||
<string name="no_valid_basal_rate">На помпе не найдены валидные записи о базалe</string>
|
||||
<string name="limiting_iob">Ограничение активного инсулина IOB до %1$.1f ед. из-за %2$s</string>
|
||||
<string name="loop_disabled">ЗЦ ОТМЕНЕН ОГРАНИЧЕНИЯМИ</string>
|
||||
|
@ -46,6 +47,7 @@
|
|||
<string name="success">Успешно</string>
|
||||
<string name="advancedsettings_title">Дополнительные настройки</string>
|
||||
<string name="extendedbolusdeliveryerror">Ошибка подачи пролонгированного болюса</string>
|
||||
<string name="aps_mode_title">Режим APS</string>
|
||||
<string name="extended_bolus">Пролонгированный болюс</string>
|
||||
<string name="paused">на паузе</string>
|
||||
<string name="tdd_total">Суммарный суточный инсулин TDD</string>
|
||||
|
@ -104,6 +106,7 @@
|
|||
<string name="loading">Загрузка…</string>
|
||||
<string name="notes_label">Заметки</string>
|
||||
<string name="remove_button">Удалить</string>
|
||||
<string name="add_new">Добавить новый</string>
|
||||
<string name="addnew_above">Добавить строку сверху</string>
|
||||
<string name="wrong_pump_data">Данные поступают с другой помпы. Измените драйвер помпы, чтобы сбросить ее состояние.</string>
|
||||
<string name="bg_label">ГК</string>
|
||||
|
@ -241,6 +244,7 @@
|
|||
<!-- CarbsReq-->
|
||||
<string name="carbsreq">Необходимо дополнительно %1$d г углеводов в течение %2$d минут</string>
|
||||
<!-- TDDStatsActivity-->
|
||||
<string name="cumulative_tdd">Накопительная суточная доза TDD</string>
|
||||
<string name="expweight">экспоненциально взвешенные TDD</string>
|
||||
<string name="basalrate">базал</string>
|
||||
<string name="bolus">Болюс</string>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<string name="pump_base_basal_rate">%1$.2f JI/h</string>
|
||||
<string name="pump_not_initialized_profile_not_set">Pumpa nie je inicializovaná, profil nenastavený!</string>
|
||||
<string name="failed_update_basal_profile">Chyba pri aktualizovaní bazálneho profilu</string>
|
||||
<string name="bolus_delivered_successfully">Bolus %1$.2f JI podaný úspešne</string>
|
||||
<string name="no_valid_basal_rate">Nenačítaný žiadny platný bazál z pumpy</string>
|
||||
<string name="limiting_iob">IOB obmedzený na %1$.1f JI: %2$s</string>
|
||||
<string name="loop_disabled">UZAVRETÝ OKRUH DEAKTIVOVANÝ OBMEDZENÍM</string>
|
||||
|
@ -46,6 +47,7 @@
|
|||
<string name="success">Úspešne</string>
|
||||
<string name="advancedsettings_title">Rozšírené nastavenia</string>
|
||||
<string name="extendedbolusdeliveryerror">Chyba pri podávaní predĺženého bolusu</string>
|
||||
<string name="aps_mode_title">APS mód</string>
|
||||
<string name="extended_bolus">Predĺžený bolus</string>
|
||||
<string name="paused">Pozastavené</string>
|
||||
<string name="tdd_total">CDD celkom</string>
|
||||
|
@ -104,6 +106,7 @@
|
|||
<string name="loading">Načítavanie...</string>
|
||||
<string name="notes_label">Poznámky</string>
|
||||
<string name="remove_button">Vymazať</string>
|
||||
<string name="add_new">Pridať nový</string>
|
||||
<string name="addnew_above">Pridať novú nad</string>
|
||||
<string name="wrong_pump_data">Dáta prichádzajú z inej pumpy. Zmeňte ovládač pre obnovenie stavu pumpy.</string>
|
||||
<string name="bg_label">Glykémia</string>
|
||||
|
@ -241,6 +244,7 @@
|
|||
<!-- CarbsReq-->
|
||||
<string name="carbsreq">Požadovaných dodatočných %1$d g sacharidov v priebehu %2$d minút</string>
|
||||
<!-- TDDStatsActivity-->
|
||||
<string name="cumulative_tdd">Kumulatívny TDD</string>
|
||||
<string name="expweight">Exponenciálne vážený TDD</string>
|
||||
<string name="basalrate">Bazál</string>
|
||||
<string name="bolus">Bolus</string>
|
||||
|
@ -465,9 +469,15 @@
|
|||
<string name="wizard_explain_tt_to">%1$s do %2$s</string>
|
||||
<string name="wizard_pump_not_available">Pumpa nedostupná!</string>
|
||||
<!-- Preferences-->
|
||||
<string name="child">Dieťa</string>
|
||||
<string name="teenage">Dospievajúci</string>
|
||||
<string name="adult">Dospelý</string>
|
||||
<string name="resistant_adult">Dospelý s nízkou citlivosťou</string>
|
||||
<string name="pregnant">Tehotenstvo</string>
|
||||
<string name="patient_age_summary">Prosím vyberte typ pacienta pre nastavenie bezpečnostných limitov</string>
|
||||
<string name="max_bolus_title">Maximálny povolený bolus [U]</string>
|
||||
<string name="max_carbs_title">Max. povolené množstvo sacharidov [g]</string>
|
||||
<string name="patient_type">Typ pacienta</string>
|
||||
<!-- Protection-->
|
||||
<string name="unlock_settings">Odomknúť nastavenia</string>
|
||||
<!-- Pumps -->
|
||||
|
|
|
@ -5,7 +5,8 @@ import info.nightscout.database.entities.Carbs
|
|||
/**
|
||||
* Sync the carbs from NS
|
||||
*/
|
||||
class SyncNsCarbsTransaction(private val carbs: List<Carbs>) : Transaction<SyncNsCarbsTransaction.TransactionResult>() {
|
||||
class SyncNsCarbsTransaction(private val carbs: List<Carbs>, private val nsClientMode: Boolean) :
|
||||
Transaction<SyncNsCarbsTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
|
@ -24,7 +25,7 @@ class SyncNsCarbsTransaction(private val carbs: List<Carbs>) : Transaction<SyncN
|
|||
result.invalidated.add(current)
|
||||
}
|
||||
// and change duration
|
||||
if (current.duration != carb.duration) {
|
||||
if (current.duration != carb.duration && nsClientMode) {
|
||||
current.amount = carb.amount
|
||||
current.duration = carb.duration
|
||||
database.carbsDao.updateExistingEntry(current)
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.math.abs
|
|||
/**
|
||||
* Sync the Extended bolus from NS
|
||||
*/
|
||||
class SyncNsExtendedBolusTransaction(private val extendedBoluses: List<ExtendedBolus>) :
|
||||
class SyncNsExtendedBolusTransaction(private val extendedBoluses: List<ExtendedBolus>, private val nsClientMode: Boolean) :
|
||||
Transaction<SyncNsExtendedBolusTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
|
@ -28,7 +28,7 @@ class SyncNsExtendedBolusTransaction(private val extendedBoluses: List<ExtendedB
|
|||
database.extendedBolusDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
if (current.duration != extendedBolus.duration) {
|
||||
if (current.duration != extendedBolus.duration && nsClientMode) {
|
||||
current.duration = extendedBolus.duration
|
||||
current.amount = extendedBolus.amount
|
||||
database.extendedBolusDao.updateExistingEntry(current)
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.math.abs
|
|||
/**
|
||||
* Sync the OfflineEvent from NS
|
||||
*/
|
||||
class SyncNsOfflineEventTransaction(private val offlineEvents: List<OfflineEvent>) :
|
||||
class SyncNsOfflineEventTransaction(private val offlineEvents: List<OfflineEvent>, private val nsClientMode: Boolean) :
|
||||
Transaction<SyncNsOfflineEventTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
|
@ -28,7 +28,7 @@ class SyncNsOfflineEventTransaction(private val offlineEvents: List<OfflineEvent
|
|||
database.offlineEventDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
if (current.duration != offlineEvent.duration) {
|
||||
if (current.duration != offlineEvent.duration && nsClientMode) {
|
||||
current.duration = offlineEvent.duration
|
||||
database.offlineEventDao.updateExistingEntry(current)
|
||||
result.updatedDuration.add(current)
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.math.abs
|
|||
/**
|
||||
* Sync the Temporary Basal from NS
|
||||
*/
|
||||
class SyncNsTemporaryBasalTransaction(private val temporaryBasals: List<TemporaryBasal>) : Transaction<SyncNsTemporaryBasalTransaction.TransactionResult>() {
|
||||
class SyncNsTemporaryBasalTransaction(private val temporaryBasals: List<TemporaryBasal>, private val nsClientMode: Boolean) : Transaction<SyncNsTemporaryBasalTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
|
@ -28,7 +28,7 @@ class SyncNsTemporaryBasalTransaction(private val temporaryBasals: List<Temporar
|
|||
database.temporaryBasalDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
if (current.duration != temporaryBasal.duration) {
|
||||
if (current.duration != temporaryBasal.duration && nsClientMode) {
|
||||
current.duration = temporaryBasal.duration
|
||||
database.temporaryBasalDao.updateExistingEntry(current)
|
||||
result.updatedDuration.add(current)
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.math.abs
|
|||
/**
|
||||
* Sync the TemporaryTarget from NS
|
||||
*/
|
||||
class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List<TemporaryTarget>) :
|
||||
class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List<TemporaryTarget>, private val nsClientMode: Boolean) :
|
||||
Transaction<SyncNsTemporaryTargetTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
|
@ -28,7 +28,7 @@ class SyncNsTemporaryTargetTransaction(private val temporaryTargets: List<Tempor
|
|||
database.temporaryTargetDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
if (current.duration != temporaryTarget.duration) {
|
||||
if (current.duration != temporaryTarget.duration && nsClientMode) {
|
||||
current.duration = temporaryTarget.duration
|
||||
database.temporaryTargetDao.updateExistingEntry(current)
|
||||
result.updatedDuration.add(current)
|
||||
|
|
|
@ -5,7 +5,7 @@ import info.nightscout.database.entities.TherapyEvent
|
|||
/**
|
||||
* Sync the TherapyEvents from NS
|
||||
*/
|
||||
class SyncNsTherapyEventTransaction(private val therapyEvents: List<TherapyEvent>) :
|
||||
class SyncNsTherapyEventTransaction(private val therapyEvents: List<TherapyEvent>, private val nsClientMode: Boolean) :
|
||||
Transaction<SyncNsTherapyEventTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
|
@ -24,7 +24,7 @@ class SyncNsTherapyEventTransaction(private val therapyEvents: List<TherapyEvent
|
|||
database.therapyEventDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
if (current.duration != therapyEvent.duration) {
|
||||
if (current.duration != therapyEvent.duration && nsClientMode) {
|
||||
current.duration = therapyEvent.duration
|
||||
database.therapyEventDao.updateExistingEntry(current)
|
||||
result.updatedDuration.add(current)
|
||||
|
|
|
@ -16,6 +16,7 @@ import info.nightscout.implementation.XDripBroadcastImpl
|
|||
import info.nightscout.implementation.androidNotification.NotificationHolderImpl
|
||||
import info.nightscout.implementation.constraints.ConstraintsImpl
|
||||
import info.nightscout.implementation.db.PersistenceLayerImpl
|
||||
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
|
||||
import info.nightscout.implementation.logging.LoggerUtilsImpl
|
||||
import info.nightscout.implementation.overview.OverviewDataImpl
|
||||
import info.nightscout.implementation.plugin.PluginStore
|
||||
|
@ -48,6 +49,7 @@ import info.nightscout.interfaces.Translator
|
|||
import info.nightscout.interfaces.XDripBroadcast
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.db.PersistenceLayer
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.logging.LoggerUtils
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
|
@ -124,5 +126,6 @@ abstract class ImplementationModule {
|
|||
@Binds fun bindsStorage(fileStorage: FileStorage): Storage
|
||||
@Binds fun bindsReceiverStatusStore(receiverStatusStoreImpl: ReceiverStatusStoreImpl): ReceiverStatusStore
|
||||
@Binds fun bindsUserEntryPresentationHelper(userEntryPresentationHelperImpl: UserEntryPresentationHelperImpl): UserEntryPresentationHelper
|
||||
@Binds fun bindsGlucoseStatusProvider(glucoseStatusProviderImpl: GlucoseStatusProviderImpl): GlucoseStatusProvider
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package info.nightscout.core.iob.iobCobCalculator
|
||||
package info.nightscout.implementation.iob
|
||||
|
||||
import dagger.Reusable
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.iob.asRounded
|
||||
import info.nightscout.core.iob.log
|
||||
import info.nightscout.interfaces.iob.GlucoseStatus
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
import info.nightscout.rx.logging.LTag
|
||||
|
@ -14,16 +15,16 @@ import kotlin.math.roundToLong
|
|||
|
||||
@Reusable
|
||||
@OpenForTesting
|
||||
class GlucoseStatusProvider @Inject constructor(
|
||||
class GlucoseStatusProviderImpl @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val dateUtil: DateUtil
|
||||
) {
|
||||
) : GlucoseStatusProvider {
|
||||
|
||||
val glucoseStatusData: GlucoseStatus?
|
||||
override val glucoseStatusData: GlucoseStatus?
|
||||
get() = getGlucoseStatusData()
|
||||
|
||||
fun getGlucoseStatusData(allowOldData: Boolean = false): GlucoseStatus? {
|
||||
override fun getGlucoseStatusData(allowOldData: Boolean): GlucoseStatus? {
|
||||
val data = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
||||
val sizeRecords = data.size
|
||||
if (sizeRecords == 0) {
|
|
@ -54,7 +54,8 @@ class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JS
|
|||
}
|
||||
|
||||
override fun getDefaultProfile(): PureProfile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
|
||||
override fun getDefaultProfileJson(): JSONObject? = getDefaultProfileName()?.let { getSpecificProfileJson(it) }
|
||||
override fun getDefaultProfileJson(): JSONObject? =
|
||||
getDefaultProfileName()?.let { getSpecificProfileJson(it) }
|
||||
|
||||
override fun getDefaultProfileName(): String? {
|
||||
val defaultProfileName = data.optString("defaultProfile")
|
||||
|
|
|
@ -24,4 +24,5 @@
|
|||
<string name="detailed_14_days">Detaljert 14 dager</string>
|
||||
<string name="day_tir">Dag TIR</string>
|
||||
<string name="night_tir">Natt TIR</string>
|
||||
<string name="carbs_short" comment="max 6 characters">Karbo</string>
|
||||
</resources>
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
<string name="in_range">Dentro da meta</string>
|
||||
<string name="above" comment="above "in range"">Acima</string>
|
||||
<string name="hba1c">HbA1c: </string>
|
||||
<string name="std_deviation">Desvio Padrão (DP ou SD): %1$s</string>
|
||||
<string name="detailed_14_days">Detalhes de 14 dias</string>
|
||||
<string name="day_tir">Tempo no Alvo (TIR) do dia</string>
|
||||
<string name="night_tir">Tempo no alvo (TIR) noturno</string>
|
||||
<string name="carbs_short" comment="max 6 characters">Carboidratos</string>
|
||||
</resources>
|
||||
|
|
|
@ -24,4 +24,5 @@
|
|||
<string name="detailed_14_days">Подробно 14 дней</string>
|
||||
<string name="day_tir">Время в целевом диапазоне днем</string>
|
||||
<string name="night_tir">Время в целевом диапазоне ночью</string>
|
||||
<string name="carbs_short" comment="max 6 characters">Угли</string>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package info.nightscout.androidaps
|
||||
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class HardLimitsMock @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val rh: ResourceHelper
|
||||
) : HardLimits {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CHILD = 0
|
||||
private const val TEENAGE = 1
|
||||
private const val ADULT = 2
|
||||
private const val RESISTANT_ADULT = 3
|
||||
private const val PREGNANT = 4
|
||||
private val MAX_BOLUS = doubleArrayOf(5.0, 10.0, 17.0, 25.0, 60.0)
|
||||
|
||||
// Very Hard Limits Ranges
|
||||
// First value is the Lowest and second value is the Highest a Limit can define
|
||||
val VERY_HARD_LIMIT_MIN_BG = doubleArrayOf(80.0, 180.0)
|
||||
val VERY_HARD_LIMIT_MAX_BG = doubleArrayOf(90.0, 200.0)
|
||||
val VERY_HARD_LIMIT_TARGET_BG = doubleArrayOf(80.0, 200.0)
|
||||
|
||||
// Very Hard Limits Ranges for Temp Targets
|
||||
val VERY_HARD_LIMIT_TEMP_MIN_BG = intArrayOf(72, 180)
|
||||
val VERY_HARD_LIMIT_TEMP_MAX_BG = intArrayOf(72, 270)
|
||||
val VERY_HARD_LIMIT_TEMP_TARGET_BG = intArrayOf(72, 200)
|
||||
val MIN_DIA = doubleArrayOf(5.0, 5.0, 5.0, 5.0, 5.0)
|
||||
val MAX_DIA = doubleArrayOf(9.0, 9.0, 9.0, 9.0, 10.0)
|
||||
val MIN_IC = doubleArrayOf(2.0, 2.0, 2.0, 2.0, 0.3)
|
||||
val MAX_IC = doubleArrayOf(100.0, 100.0, 100.0, 100.0, 100.0)
|
||||
const val MIN_ISF = 2.0 // mgdl
|
||||
const val MAX_ISF = 1000.0 // mgdl
|
||||
val MAX_IOB_AMA = doubleArrayOf(3.0, 5.0, 7.0, 12.0, 25.0)
|
||||
val MAX_IOB_SMB = doubleArrayOf(7.0, 13.0, 22.0, 30.0, 70.0)
|
||||
val MAX_BASAL = doubleArrayOf(2.0, 5.0, 10.0, 12.0, 25.0)
|
||||
|
||||
//LGS Hard limits
|
||||
//No IOB at all
|
||||
const val MAX_IOB_LGS = 0.0
|
||||
|
||||
}
|
||||
|
||||
private fun loadAge(): Int = when (sp.getString(info.nightscout.core.utils.R.string.key_age, "")) {
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_child) -> CHILD
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_teenage) -> TEENAGE
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_adult) -> ADULT
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_resistantadult) -> RESISTANT_ADULT
|
||||
rh.gs(info.nightscout.core.utils.R.string.key_pregnant) -> PREGNANT
|
||||
else -> ADULT
|
||||
}
|
||||
|
||||
override fun maxBolus(): Double = MAX_BOLUS[loadAge()]
|
||||
override fun maxIobAMA(): Double = MAX_IOB_AMA[loadAge()]
|
||||
override fun maxIobSMB(): Double = MAX_IOB_SMB[loadAge()]
|
||||
override fun maxBasal(): Double = MAX_BASAL[loadAge()]
|
||||
override fun minDia(): Double = MIN_DIA[loadAge()]
|
||||
override fun maxDia(): Double = MAX_DIA[loadAge()]
|
||||
override fun minIC(): Double = MIN_IC[loadAge()]
|
||||
override fun maxIC(): Double = MAX_IC[loadAge()]
|
||||
|
||||
// safety checks
|
||||
override fun checkHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Boolean =
|
||||
value == verifyHardLimits(value, valueName, lowLimit, highLimit)
|
||||
|
||||
override fun isInRange(value: Double, lowLimit: Double, highLimit: Double): Boolean =
|
||||
value in lowLimit..highLimit
|
||||
|
||||
override fun verifyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Double {
|
||||
var newValue = value
|
||||
if (newValue < lowLimit || newValue > highLimit) {
|
||||
newValue = max(newValue, lowLimit)
|
||||
newValue = min(newValue, highLimit)
|
||||
}
|
||||
return newValue
|
||||
}
|
||||
}
|
|
@ -14,8 +14,10 @@ import info.nightscout.interfaces.iob.IobCobCalculator
|
|||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.profile.ProfileStore
|
||||
import info.nightscout.interfaces.utils.HardLimits
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import org.json.JSONObject
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
|
@ -37,25 +39,46 @@ open class TestBaseWithProfile : TestBase() {
|
|||
@Mock lateinit var profileFunction: ProfileFunction
|
||||
@Mock lateinit var config: Config
|
||||
@Mock lateinit var context: Context
|
||||
@Mock lateinit var sp: SP
|
||||
|
||||
private lateinit var hardLimits: HardLimits
|
||||
lateinit var dateUtil: DateUtil
|
||||
val rxBus = RxBus(aapsSchedulers, aapsLogger)
|
||||
|
||||
val profileInjector = HasAndroidInjector { AndroidInjector { } }
|
||||
val profileInjector = HasAndroidInjector {
|
||||
AndroidInjector {
|
||||
if (it is ProfileStoreObject) {
|
||||
it.aapsLogger = aapsLogger
|
||||
it.activePlugin = activePluginProvider
|
||||
it.config = config
|
||||
it.rh = rh
|
||||
it.rxBus = rxBus
|
||||
it.hardLimits = hardLimits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var validProfileJSON: String
|
||||
private lateinit var invalidProfileJSON: String
|
||||
lateinit var validProfile: ProfileSealed.Pure
|
||||
lateinit var effectiveProfileSwitch: EffectiveProfileSwitch
|
||||
lateinit var testPumpPlugin: TestPumpPlugin
|
||||
|
||||
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
|
||||
|
||||
@BeforeEach
|
||||
fun prepareMock() {
|
||||
invalidProfileJSON = "{\"dia\":\"1\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
||||
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
||||
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||
validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
||||
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
||||
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||
testPumpPlugin = TestPumpPlugin(profileInjector)
|
||||
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
||||
dateUtil = Mockito.spy(DateUtil(context))
|
||||
`when`(dateUtil.now()).thenReturn(1656358822000)
|
||||
hardLimits = HardLimitsMock(sp, rh)
|
||||
validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
|
||||
effectiveProfileSwitch = EffectiveProfileSwitch(
|
||||
timestamp = dateUtil.now(),
|
||||
|
@ -175,4 +198,23 @@ open class TestBaseWithProfile : TestBase() {
|
|||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
|
||||
fun getInvalidProfileStore1(): ProfileStore {
|
||||
val json = JSONObject()
|
||||
val store = JSONObject()
|
||||
store.put(TESTPROFILENAME, JSONObject(invalidProfileJSON))
|
||||
json.put("defaultProfile", TESTPROFILENAME)
|
||||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
|
||||
fun getInvalidProfileStore2(): ProfileStore {
|
||||
val json = JSONObject()
|
||||
val store = JSONObject()
|
||||
store.put(TESTPROFILENAME, JSONObject(validProfileJSON))
|
||||
store.put("invalid", JSONObject(invalidProfileJSON))
|
||||
json.put("defaultProfile", TESTPROFILENAME + "invalid")
|
||||
json.put("store", store)
|
||||
return ProfileStoreObject(profileInjector, json, dateUtil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class TestPumpPlugin(val injector: HasAndroidInjector) : Pump {
|
|||
val lastData = 0L
|
||||
|
||||
val baseBasal = 0.0
|
||||
override val pumpDescription = PumpDescription()
|
||||
override var pumpDescription = PumpDescription()
|
||||
|
||||
override fun isInitialized(): Boolean = true
|
||||
override fun isSuspended(): Boolean = false
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCalculator
|
||||
package info.nightscout.implementation.iob
|
||||
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.core.iob.asRounded
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.log
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.interfaces.aps.AutosensDataStore
|
||||
|
@ -10,16 +9,15 @@ import info.nightscout.interfaces.iob.GlucoseStatus
|
|||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
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.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito
|
||||
|
||||
/**
|
||||
* Created by mike on 26.03.2018.
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class GlucoseStatusTest : TestBase() {
|
||||
|
||||
@Mock lateinit var dateUtil: DateUtil
|
||||
|
@ -28,85 +26,85 @@ class GlucoseStatusTest : TestBase() {
|
|||
|
||||
@BeforeEach
|
||||
fun prepare() {
|
||||
`when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore)
|
||||
Mockito.`when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore)
|
||||
}
|
||||
|
||||
@Test fun toStringShouldBeOverloaded() {
|
||||
val glucoseStatus = GlucoseStatus(glucose = 0.0, noise = 0.0, delta = 0.0, shortAvgDelta = 0.0, longAvgDelta = 0.0, date = 0)
|
||||
Assert.assertEquals(true, glucoseStatus.log().contains("Delta"))
|
||||
Assertions.assertEquals(true, glucoseStatus.log().contains("Delta"))
|
||||
}
|
||||
|
||||
@Test fun roundTest() {
|
||||
val glucoseStatus = GlucoseStatus(glucose = 100.11111, noise = 0.0, delta = 0.0, shortAvgDelta = 0.0, longAvgDelta = 0.0, date = 0)
|
||||
Assert.assertEquals(100.1, glucoseStatus.asRounded().glucose, 0.0001)
|
||||
Assertions.assertEquals(100.1, glucoseStatus.asRounded().glucose, 0.0001)
|
||||
}
|
||||
|
||||
@Test fun calculateValidGlucoseStatus() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData())
|
||||
val glucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001)
|
||||
Assert.assertEquals(-2.0, glucoseStatus.delta, 0.001)
|
||||
Assert.assertEquals(-2.5, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value
|
||||
Assert.assertEquals(-2.0, glucoseStatus.longAvgDelta, 0.001) // -2 -2 -2 -2
|
||||
Assert.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateValidBgData())
|
||||
val glucoseStatus = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assertions.assertEquals(214.0, glucoseStatus.glucose, 0.001)
|
||||
Assertions.assertEquals(-2.0, glucoseStatus.delta, 0.001)
|
||||
Assertions.assertEquals(-2.5, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value
|
||||
Assertions.assertEquals(-2.0, glucoseStatus.longAvgDelta, 0.001) // -2 -2 -2 -2
|
||||
Assertions.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
}
|
||||
|
||||
@Test fun calculateMostRecentGlucoseStatus() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateMostRecentBgData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assert.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2
|
||||
Assert.assertEquals(-1.0, glucoseStatus.delta, 0.001)
|
||||
Assert.assertEquals(-1.0, glucoseStatus.shortAvgDelta, 0.001)
|
||||
Assert.assertEquals(0.0, glucoseStatus.longAvgDelta, 0.001)
|
||||
Assert.assertEquals(1514766900000L, glucoseStatus.date) // latest date, even when averaging
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateMostRecentBgData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assertions.assertEquals(215.0, glucoseStatus.glucose, 0.001) // (214+216) / 2
|
||||
Assertions.assertEquals(-1.0, glucoseStatus.delta, 0.001)
|
||||
Assertions.assertEquals(-1.0, glucoseStatus.shortAvgDelta, 0.001)
|
||||
Assertions.assertEquals(0.0, glucoseStatus.longAvgDelta, 0.001)
|
||||
Assertions.assertEquals(1514766900000L, glucoseStatus.date) // latest date, even when averaging
|
||||
}
|
||||
|
||||
@Test fun oneRecordShouldProduceZeroDeltas() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assert.assertEquals(214.0, glucoseStatus.glucose, 0.001)
|
||||
Assert.assertEquals(0.0, glucoseStatus.delta, 0.001)
|
||||
Assert.assertEquals(0.0, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value
|
||||
Assert.assertEquals(0.0, glucoseStatus.longAvgDelta, 0.001) // -2 -2 -2 -2
|
||||
Assert.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOneCurrentRecordBgData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assertions.assertEquals(214.0, glucoseStatus.glucose, 0.001)
|
||||
Assertions.assertEquals(0.0, glucoseStatus.delta, 0.001)
|
||||
Assertions.assertEquals(0.0, glucoseStatus.shortAvgDelta, 0.001) // -2 -2.5 -3 deltas are relative to current value
|
||||
Assertions.assertEquals(0.0, glucoseStatus.longAvgDelta, 0.001) // -2 -2 -2 -2
|
||||
Assertions.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
}
|
||||
|
||||
@Test fun insufficientDataShouldReturnNull() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateInsufficientBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
|
||||
Assert.assertEquals(null, glucoseStatus)
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateInsufficientBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
|
||||
Assertions.assertEquals(null, glucoseStatus)
|
||||
}
|
||||
|
||||
@Test fun oldDataShouldReturnNull() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
|
||||
Assert.assertEquals(null, glucoseStatus)
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData
|
||||
Assertions.assertEquals(null, glucoseStatus)
|
||||
}
|
||||
|
||||
@Test fun returnOldDataIfAllowed() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true)
|
||||
Assert.assertNotEquals(null, glucoseStatus)
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateOldBgData())
|
||||
val glucoseStatus: GlucoseStatus? = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).getGlucoseStatusData(true)
|
||||
Assertions.assertNotEquals(null, glucoseStatus)
|
||||
}
|
||||
|
||||
@Test fun averageShouldNotFailOnEmptyArray() {
|
||||
Assert.assertEquals(0.0, GlucoseStatusProvider.average(ArrayList()), 0.001)
|
||||
Assertions.assertEquals(0.0, GlucoseStatusProviderImpl.average(ArrayList()), 0.001)
|
||||
}
|
||||
|
||||
@Test fun calculateGlucoseStatusForLibreTestBgData() {
|
||||
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateLibreTestData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProvider(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assert.assertEquals(100.0, glucoseStatus.glucose, 0.001) //
|
||||
Assert.assertEquals(-10.0, glucoseStatus.delta, 0.001)
|
||||
Assert.assertEquals(-10.0, glucoseStatus.shortAvgDelta, 0.001)
|
||||
Assert.assertEquals(-10.0, glucoseStatus.longAvgDelta, 0.001)
|
||||
Assert.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
Mockito.`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(generateLibreTestData())
|
||||
val glucoseStatus: GlucoseStatus = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculatorPlugin, dateUtil).glucoseStatusData!!
|
||||
Assertions.assertEquals(100.0, glucoseStatus.glucose, 0.001) //
|
||||
Assertions.assertEquals(-10.0, glucoseStatus.delta, 0.001)
|
||||
Assertions.assertEquals(-10.0, glucoseStatus.shortAvgDelta, 0.001)
|
||||
Assertions.assertEquals(-10.0, glucoseStatus.longAvgDelta, 0.001)
|
||||
Assertions.assertEquals(1514766900000L, glucoseStatus.date) // latest date
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun initMocking() {
|
||||
`when`(dateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs())
|
||||
`when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore)
|
||||
Mockito.`when`(dateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs())
|
||||
Mockito.`when`(iobCobCalculatorPlugin.ads).thenReturn(autosensDataStore)
|
||||
}
|
||||
|
||||
// [{"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}]
|
||||
|
@ -154,13 +152,40 @@ class GlucoseStatusTest : TestBase() {
|
|||
// Now
|
||||
list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
// One minute ago
|
||||
list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime - 1000 * 60 * 1, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
list.add(
|
||||
GlucoseValue(
|
||||
raw = 0.0,
|
||||
noise = 0.0,
|
||||
value = latestReading,
|
||||
timestamp = endTime - 1000 * 60 * 1,
|
||||
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||
)
|
||||
)
|
||||
// Two minutes ago
|
||||
list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime - 1000 * 60 * 2, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
list.add(
|
||||
GlucoseValue(
|
||||
raw = 0.0,
|
||||
noise = 0.0,
|
||||
value = latestReading,
|
||||
timestamp = endTime - 1000 * 60 * 2,
|
||||
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||
)
|
||||
)
|
||||
|
||||
// Three minutes and beyond at constant rate
|
||||
for (i in 3..49)
|
||||
list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading + i * 2, timestamp = endTime - 1000 * 60 * i, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
|
||||
list.add(
|
||||
GlucoseValue(
|
||||
raw = 0.0,
|
||||
noise = 0.0,
|
||||
value = latestReading + i * 2,
|
||||
timestamp = endTime - 1000 * 60 * i,
|
||||
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
|
||||
trendArrow = GlucoseValue.TrendArrow.FLAT
|
||||
)
|
||||
)
|
||||
return list
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.interfaces
|
||||
package info.nightscout.implementation.profile
|
||||
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import info.nightscout.interfaces.profile.PureProfile
|
|
@ -37,7 +37,7 @@ import info.nightscout.shared.interfaces.ResourceHelper
|
|||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
|
@ -51,7 +51,6 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
|
||||
@Mock lateinit var constraintChecker: Constraints
|
||||
@Mock lateinit var activePlugin: ActivePlugin
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var powerManager: PowerManager
|
||||
@Mock lateinit var repository: AppRepository
|
||||
@Mock lateinit var uiInteraction: UiInteraction
|
||||
|
@ -115,7 +114,6 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
}
|
||||
|
||||
private lateinit var commandQueue: CommandQueueImplementation
|
||||
private lateinit var testPumpPlugin: TestPumpPlugin
|
||||
|
||||
@BeforeEach
|
||||
fun prepare() {
|
||||
|
@ -170,108 +168,108 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
commandQueue.handler = handler
|
||||
|
||||
// start with empty queue
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// add bolus command
|
||||
commandQueue.bolus(DetailedBolusInfo(), null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
|
||||
commandQueue.waitForFinishedThread()
|
||||
Thread.sleep(1000)
|
||||
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doTests() {
|
||||
|
||||
// start with empty queue
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// add bolus command
|
||||
commandQueue.bolus(DetailedBolusInfo(), null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
|
||||
// add READSTATUS
|
||||
commandQueue.readStatus("anyString", null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// adding another bolus should remove the first one (size still == 2)
|
||||
commandQueue.bolus(DetailedBolusInfo(), null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// clear the queue should reset size
|
||||
commandQueue.clear()
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// add tempbasal
|
||||
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
|
||||
// add tempbasal percent. it should replace previous TEMPBASAL
|
||||
commandQueue.tempBasalPercent(0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
|
||||
// cancel tempbasal it should replace previous TEMPBASAL
|
||||
commandQueue.cancelTempBasal(false, null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
|
||||
// add extended bolus
|
||||
commandQueue.extendedBolus(1.0, 30, null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// add extended should remove previous extended setting
|
||||
commandQueue.extendedBolus(1.0, 30, null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// cancel extended bolus should replace previous extended
|
||||
commandQueue.cancelExtended(null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// add setProfile
|
||||
// TODO: this crash the test
|
||||
// commandQueue.setProfile(validProfile, null)
|
||||
// Assert.assertEquals(3, commandQueue.size())
|
||||
// Assertions.assertEquals(3, commandQueue.size())
|
||||
|
||||
// add loadHistory
|
||||
commandQueue.loadHistory(0.toByte(), null)
|
||||
Assert.assertEquals(3, commandQueue.size())
|
||||
Assertions.assertEquals(3, commandQueue.size())
|
||||
|
||||
// add loadEvents
|
||||
commandQueue.loadEvents(null)
|
||||
Assert.assertEquals(4, commandQueue.size())
|
||||
Assertions.assertEquals(4, commandQueue.size())
|
||||
commandQueue.clear()
|
||||
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, PumpSync.TemporaryBasalType.NORMAL, null)
|
||||
commandQueue.pickup()
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assert.assertNotNull(commandQueue.performing)
|
||||
Assert.assertEquals(Command.CommandType.TEMPBASAL, commandQueue.performing?.commandType)
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertNotNull(commandQueue.performing)
|
||||
Assertions.assertEquals(Command.CommandType.TEMPBASAL, commandQueue.performing?.commandType)
|
||||
commandQueue.resetPerforming()
|
||||
Assert.assertNull(commandQueue.performing)
|
||||
Assertions.assertNull(commandQueue.performing)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun callingCancelAllBolusesClearsQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
val smb = DetailedBolusInfo()
|
||||
smb.lastKnownBolusTime = System.currentTimeMillis()
|
||||
smb.bolusType = DetailedBolusInfo.BolusType.SMB
|
||||
commandQueue.bolus(smb, null)
|
||||
commandQueue.bolus(DetailedBolusInfo(), null)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.cancelAllBoluses(null)
|
||||
|
||||
// then
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun smbIsRejectedIfABolusIsQueued() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.bolus(DetailedBolusInfo(), null)
|
||||
|
@ -280,14 +278,14 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
val queued: Boolean = commandQueue.bolus(smb, null)
|
||||
|
||||
// then
|
||||
Assert.assertFalse(queued)
|
||||
Assert.assertEquals(commandQueue.size(), 1)
|
||||
Assertions.assertFalse(queued)
|
||||
Assertions.assertEquals(commandQueue.size(), 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun smbIsRejectedIfLastKnownBolusIsOutdated() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
val bolus = DetailedBolusInfo()
|
||||
|
@ -296,14 +294,14 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
val queued: Boolean = commandQueue.bolus(bolus, null)
|
||||
|
||||
// then
|
||||
Assert.assertFalse(queued)
|
||||
Assert.assertEquals(commandQueue.size(), 0)
|
||||
Assertions.assertFalse(queued)
|
||||
Assertions.assertEquals(commandQueue.size(), 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isCustomCommandRunning() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
|
||||
|
@ -311,201 +309,201 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
commandQueue.pickup()
|
||||
|
||||
// then
|
||||
Assert.assertTrue(queued1)
|
||||
Assert.assertTrue(queued2)
|
||||
Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand1::class.java))
|
||||
Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand2::class.java))
|
||||
Assert.assertFalse(commandQueue.isCustomCommandInQueue(CustomCommand3::class.java))
|
||||
Assertions.assertTrue(queued1)
|
||||
Assertions.assertTrue(queued2)
|
||||
Assertions.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand1::class.java))
|
||||
Assertions.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand2::class.java))
|
||||
Assertions.assertFalse(commandQueue.isCustomCommandInQueue(CustomCommand3::class.java))
|
||||
|
||||
Assert.assertTrue(commandQueue.isCustomCommandRunning(CustomCommand1::class.java))
|
||||
Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand2::class.java))
|
||||
Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand3::class.java))
|
||||
Assertions.assertTrue(commandQueue.isCustomCommandRunning(CustomCommand1::class.java))
|
||||
Assertions.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand2::class.java))
|
||||
Assertions.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand3::class.java))
|
||||
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSetUserOptionsCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.setUserOptions(null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.SET_USER_SETTINGS))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.SET_USER_SETTINGS))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.setUserOptions(null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isLoadEventsCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.loadEvents(null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_EVENTS))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_EVENTS))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.loadEvents(null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isLoadTDDsCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.loadTDDs(null)
|
||||
|
||||
// then
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.loadTDDs(null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isLoadHistoryCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.loadHistory(0, null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_HISTORY))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.LOAD_HISTORY))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.loadHistory(0, null)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isProfileSetCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
testPumpPlugin.isProfileSet = true
|
||||
commandQueue.setProfile(validProfile, false, object : Callback() {
|
||||
override fun run() {
|
||||
Assert.assertTrue(result.success)
|
||||
Assert.assertFalse(result.enacted)
|
||||
Assertions.assertTrue(result.success)
|
||||
Assertions.assertFalse(result.enacted)
|
||||
}
|
||||
})
|
||||
|
||||
// then
|
||||
// the same profile -> ignore
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
// different should be added
|
||||
testPumpPlugin.isProfileSet = false
|
||||
commandQueue.setProfile(validProfile, false, object : Callback() {
|
||||
override fun run() {
|
||||
Assert.assertTrue(result.success)
|
||||
Assert.assertTrue(result.enacted)
|
||||
Assertions.assertTrue(result.success)
|
||||
Assertions.assertTrue(result.enacted)
|
||||
}
|
||||
})
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
// next should be ignored
|
||||
commandQueue.setProfile(validProfile, false, object : Callback() {
|
||||
override fun run() {
|
||||
Assert.assertTrue(result.success)
|
||||
Assertions.assertTrue(result.success)
|
||||
}
|
||||
})
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
testPumpPlugin.isProfileSet = true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isStopCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.stopPump(null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.STOP_PUMP))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.STOP_PUMP))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isStarCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.startPump(null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.START_PUMP))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.START_PUMP))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isSetTbrNotificationCommandInQueue() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
commandQueue.setTBROverNotification(null, true)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(commandQueue.isLastScheduled(Command.CommandType.INSIGHT_SET_TBR_OVER_ALARM))
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.isLastScheduled(Command.CommandType.INSIGHT_SET_TBR_OVER_ALARM))
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun differentCustomCommandsAllowed() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
|
||||
val queued2 = commandQueue.customCommand(CustomCommand2(), null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(queued1)
|
||||
Assert.assertTrue(queued2)
|
||||
Assert.assertEquals(2, commandQueue.size())
|
||||
Assertions.assertTrue(queued1)
|
||||
Assertions.assertTrue(queued2)
|
||||
Assertions.assertEquals(2, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sameCustomCommandNotAllowed() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
val queued1 = commandQueue.customCommand(CustomCommand1(), null)
|
||||
val queued2 = commandQueue.customCommand(CustomCommand1(), null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(queued1)
|
||||
Assert.assertFalse(queued2)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(queued1)
|
||||
Assertions.assertFalse(queued2)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readStatusTwiceIsNotAllowed() {
|
||||
// given
|
||||
Assert.assertEquals(0, commandQueue.size())
|
||||
Assertions.assertEquals(0, commandQueue.size())
|
||||
|
||||
// when
|
||||
val queued1 = commandQueue.readStatus("1", null)
|
||||
val queued2 = commandQueue.readStatus("2", null)
|
||||
|
||||
// then
|
||||
Assert.assertTrue(queued1)
|
||||
Assert.assertFalse(queued2)
|
||||
Assert.assertEquals(1, commandQueue.size())
|
||||
Assert.assertTrue(commandQueue.statusInQueue())
|
||||
Assertions.assertTrue(queued1)
|
||||
Assertions.assertFalse(queued2)
|
||||
Assertions.assertEquals(1, commandQueue.size())
|
||||
Assertions.assertTrue(commandQueue.statusInQueue())
|
||||
}
|
||||
|
||||
private class CustomCommand1 : CustomCommand {
|
||||
|
|
|
@ -17,7 +17,6 @@ import info.nightscout.interfaces.pump.PumpSync
|
|||
import info.nightscout.interfaces.pump.defs.PumpDescription
|
||||
import info.nightscout.interfaces.queue.Command
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
@ -29,7 +28,6 @@ class QueueThreadTest : TestBaseWithProfile() {
|
|||
|
||||
@Mock lateinit var constraintChecker: Constraints
|
||||
@Mock lateinit var activePlugin: ActivePlugin
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var powerManager: PowerManager
|
||||
@Mock lateinit var repository: AppRepository
|
||||
@Mock lateinit var androidPermission: AndroidPermission
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package info.nightscout.core.wizard
|
||||
package info.nightscout.implementation.wizard
|
||||
|
||||
import android.content.Context
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.androidaps.TestPumpPlugin
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.wizard.BolusWizard
|
||||
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
|
||||
import info.nightscout.interfaces.GlucoseUnit
|
||||
import info.nightscout.interfaces.aps.AutosensDataStore
|
||||
import info.nightscout.interfaces.aps.Loop
|
||||
|
@ -25,7 +26,6 @@ import org.junit.Assert
|
|||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
|
||||
class BolusWizardTest : TestBase() {
|
||||
|
@ -56,7 +56,7 @@ class BolusWizardTest : TestBase() {
|
|||
it.loop = loop
|
||||
it.dateUtil = dateUtil
|
||||
it.iobCobCalculator = iobCobCalculator
|
||||
it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil)
|
||||
it.glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,19 +66,19 @@ class BolusWizardTest : TestBase() {
|
|||
@Suppress("SameParameterValue")
|
||||
private fun setupProfile(targetLow: Double, targetHigh: Double, insulinSensitivityFactor: Double, insulinToCarbRatio: Double): Profile {
|
||||
val profile = Mockito.mock(Profile::class.java)
|
||||
`when`(profile.getTargetLowMgdl()).thenReturn(targetLow)
|
||||
`when`(profile.getTargetLowMgdl()).thenReturn(targetHigh)
|
||||
`when`(profile.getIsfMgdl()).thenReturn(insulinSensitivityFactor)
|
||||
`when`(profile.getIc()).thenReturn(insulinToCarbRatio)
|
||||
Mockito.`when`(profile.getTargetLowMgdl()).thenReturn(targetLow)
|
||||
Mockito.`when`(profile.getTargetLowMgdl()).thenReturn(targetHigh)
|
||||
Mockito.`when`(profile.getIsfMgdl()).thenReturn(insulinSensitivityFactor)
|
||||
Mockito.`when`(profile.getIc()).thenReturn(insulinToCarbRatio)
|
||||
|
||||
`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
|
||||
`when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis()))
|
||||
`when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis()))
|
||||
`when`(activePlugin.activePump).thenReturn(testPumpPlugin)
|
||||
Mockito.`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
|
||||
Mockito.`when`(iobCobCalculator.calculateIobFromBolus()).thenReturn(IobTotal(System.currentTimeMillis()))
|
||||
Mockito.`when`(iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended()).thenReturn(IobTotal(System.currentTimeMillis()))
|
||||
Mockito.`when`(activePlugin.activePump).thenReturn(testPumpPlugin)
|
||||
testPumpPlugin.pumpDescription = PumpDescription().also {
|
||||
it.bolusStep = pumpBolusStep
|
||||
}
|
||||
`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
||||
Mockito.`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
||||
|
||||
Mockito.doAnswer { invocation: InvocationOnMock ->
|
||||
invocation.getArgument<Constraint<Double>>(0)
|
|
@ -110,7 +110,7 @@ function enable_smb(
|
|||
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 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
|
||||
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
|
||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
||||
} 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) {
|
||||
} else if ( bg > 60 && flatBGsDetected) {
|
||||
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||
rT.reason = "CGM was just calibrated";
|
||||
} else {
|
||||
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 && 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 (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && flatBGsDetected )) {
|
||||
if (currenttemp.rate > basal) { // high temp is running
|
||||
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||
rT.deliverAt = deliverAt;
|
||||
|
|
|
@ -110,7 +110,7 @@ function enable_smb(
|
|||
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 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
|
||||
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
|
||||
//cherry pick from oref upstream dev cb8e94990301277fb1016c778b4e9efa55a6edbc
|
||||
} 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) {
|
||||
} else if ( bg > 60 && flatBGsDetected) {
|
||||
if ( glucose_status.last_cal && glucose_status.last_cal < 3 ) {
|
||||
rT.reason = "CGM was just calibrated";
|
||||
} else {
|
||||
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 && 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 (bg <= 10 || bg === 38 || noise >= 3 || minAgo > 12 || minAgo < -5 || ( bg > 60 && flatBGsDetected )) {
|
||||
if (currenttemp.rate > basal) { // high temp is running
|
||||
rT.reason += ". Replacing high temp basal of "+currenttemp.rate+" with neutral temp of "+basal;
|
||||
rT.deliverAt = deliverAt;
|
||||
|
|
|
@ -162,7 +162,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
|
|||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
flatBGsDetected: Boolean
|
||||
) {
|
||||
this.profile = JSONObject()
|
||||
this.profile.put("max_iob", maxIob)
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.extensions.target
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.utils.MidnightUtils
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.database.ValueWrapper
|
||||
|
@ -14,6 +13,7 @@ import info.nightscout.interfaces.aps.AutosensResult
|
|||
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
|
|
|
@ -57,7 +57,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
private var microBolusAllowed = false
|
||||
private var smbAlwaysAllowed = false
|
||||
private var currentTime: Long = 0
|
||||
private var saveCgmSource = false
|
||||
private var flatBGsDetected = false
|
||||
|
||||
override var currentTempParam: 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, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||
aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected")
|
||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||
val rhino = Context.enter()
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
|
@ -119,7 +119,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
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
|
||||
scriptDebug = LoggerCallback.scriptDebug
|
||||
|
@ -174,7 +174,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
flatBGsDetected: Boolean
|
||||
) {
|
||||
val pump = activePlugin.activePump
|
||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||
|
@ -262,7 +262,7 @@ class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader:
|
|||
this.microBolusAllowed = microBolusAllowed
|
||||
smbAlwaysAllowed = advancedFiltering
|
||||
currentTime = now
|
||||
saveCgmSource = isSaveCgmSource
|
||||
this.flatBGsDetected = flatBGsDetected
|
||||
}
|
||||
|
||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||
|
|
|
@ -6,7 +6,6 @@ import androidx.preference.SwitchPreference
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.extensions.target
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.utils.MidnightUtils
|
||||
import info.nightscout.database.ValueWrapper
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
|
@ -14,8 +13,10 @@ import info.nightscout.interfaces.aps.APS
|
|||
import info.nightscout.interfaces.aps.AutosensResult
|
||||
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
||||
import info.nightscout.interfaces.aps.SMBDefaults
|
||||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
|
@ -55,7 +56,8 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
private val sp: SP,
|
||||
private val dateUtil: DateUtil,
|
||||
private val repository: AppRepository,
|
||||
private val glucoseStatusProvider: GlucoseStatusProvider
|
||||
private val glucoseStatusProvider: GlucoseStatusProvider,
|
||||
private val bgQualityCheck: BgQualityCheck
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.APS)
|
||||
|
@ -191,6 +193,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
constraintChecker.isUAMEnabled(it)
|
||||
inputConstraints.copyReasons(it)
|
||||
}
|
||||
val flatBGsDetected = bgQualityCheck.state == BgQualityCheck.State.FLAT
|
||||
profiler.log(LTag.APS, "detectSensitivityAndCarbAbsorption()", startPart)
|
||||
profiler.log(LTag.APS, "SMB data gathering", start)
|
||||
start = System.currentTimeMillis()
|
||||
|
@ -207,7 +210,7 @@ class OpenAPSSMBPlugin @Inject constructor(
|
|||
smbAllowed.value(),
|
||||
uam.value(),
|
||||
advancedFiltering.value(),
|
||||
activePlugin.activeBgSource.javaClass.simpleName == "DexcomPlugin"
|
||||
flatBGsDetected
|
||||
)
|
||||
val now = System.currentTimeMillis()
|
||||
val determineBasalResultSMB = determineBasalAdapterSMBJS.invoke()
|
||||
|
|
|
@ -59,7 +59,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
private var microBolusAllowed = false
|
||||
private var smbAlwaysAllowed = false
|
||||
private var currentTime: Long = 0
|
||||
private var saveCgmSource = false
|
||||
private var flatBGsDetected = false
|
||||
|
||||
override var currentTempParam: 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, "SMBAlwaysAllowed: $smbAlwaysAllowed")
|
||||
aapsLogger.debug(LTag.APS, "CurrentTime: $currentTime")
|
||||
aapsLogger.debug(LTag.APS, "isSaveCgmSource: $saveCgmSource")
|
||||
aapsLogger.debug(LTag.APS, "flatBGsDetected: $flatBGsDetected")
|
||||
var determineBasalResultSMB: DetermineBasalResultSMB? = null
|
||||
val rhino = Context.enter()
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
|
@ -121,7 +121,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
java.lang.Boolean.valueOf(microBolusAllowed),
|
||||
makeParam(null, rhino, scope), // reservoir data as undefined
|
||||
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
|
||||
scriptDebug = LoggerCallback.scriptDebug
|
||||
|
@ -176,7 +176,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
microBolusAllowed: Boolean,
|
||||
uamAllowed: Boolean,
|
||||
advancedFiltering: Boolean,
|
||||
isSaveCgmSource: Boolean
|
||||
flatBGsDetected: Boolean
|
||||
) {
|
||||
val pump = activePlugin.activePump
|
||||
val pumpBolusStep = pump.pumpDescription.bolusStep
|
||||
|
@ -312,7 +312,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
this.microBolusAllowed = microBolusAllowed
|
||||
smbAlwaysAllowed = advancedFiltering
|
||||
currentTime = now
|
||||
saveCgmSource = isSaveCgmSource
|
||||
this.flatBGsDetected = flatBGsDetected
|
||||
}
|
||||
|
||||
private fun makeParam(jsonObject: JSONObject?, rhino: Context, scope: Scriptable): Any {
|
||||
|
|
|
@ -3,11 +3,12 @@ package info.nightscout.plugins.aps.openAPSSMBDynamicISF
|
|||
import android.content.Context
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.aps.DetermineBasalAdapter
|
||||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
|
@ -42,7 +43,8 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
|||
dateUtil: DateUtil,
|
||||
repository: AppRepository,
|
||||
glucoseStatusProvider: GlucoseStatusProvider,
|
||||
private val config: Config
|
||||
private val config: Config,
|
||||
private val bgQualityCheck: BgQualityCheck
|
||||
) : OpenAPSSMBPlugin(
|
||||
injector,
|
||||
aapsLogger,
|
||||
|
@ -58,7 +60,8 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
|||
sp,
|
||||
dateUtil,
|
||||
repository,
|
||||
glucoseStatusProvider
|
||||
glucoseStatusProvider,
|
||||
bgQualityCheck
|
||||
) {
|
||||
|
||||
init {
|
||||
|
|
|
@ -90,12 +90,28 @@
|
|||
<!-- Autotune -->
|
||||
<string name="insulin_peak">Пик</string>
|
||||
<!-- Loop -->
|
||||
<string name="run_now">Выполнить сейчас</string>
|
||||
<string name="smb_frequency_exceeded">Болюс был подан в течение последних трех минут, минуя супер микро болюс SMB</string>
|
||||
<string name="pump_not_initialized">Помпа не инициализирована!</string>
|
||||
<string name="loop_shortname">ЗЦ</string>
|
||||
<string name="description_loop">Активировать или деактивировать запуск цикла.</string>
|
||||
<string name="no_aps_selected">APS не выбрана или не выдала результат</string>
|
||||
<string name="ignore5m">Игнорировать 5 м</string>
|
||||
<string name="ignore15m">Игнорировать 15 м</string>
|
||||
<string name="ignore30m">Игнорировать 30 м</string>
|
||||
<string name="carbs_suggestion">Предложены углеводы</string>
|
||||
<string name="open_loop_new_suggestion">Есть новое предложение</string>
|
||||
<string name="basal_set_correctly">Базал задан корректно</string>
|
||||
<string name="last_run_label">Предыдущее выполнение</string>
|
||||
<string name="loop_aps_label">Система ИПЖ</string>
|
||||
<string name="request_label">Запрос</string>
|
||||
<string name="loop_constraints_processed_label">После наложенных ограничений</string>
|
||||
<string name="loop_tbr_request_time_label">Время запроса временной базальной скорости</string>
|
||||
<string name="loop_tbr_execution_time_label">Время выполнения временной базальной скорости</string>
|
||||
<string name="loop_tbr_set_by_pump_label">Временный базал задан помпой</string>
|
||||
<string name="loop_smb_request_time_label">Время запроса микроболюса SMB</string>
|
||||
<string name="loop_smb_execution_time_label">Время выполнения микроболюса SMB</string>
|
||||
<string name="loop_smb_set_by_pump_label">Супер микро болюс SMB задан помпой</string>
|
||||
<string name="loop_open_mode_min_change">Минимальный запрос на изменения [%]</string>
|
||||
<string name="loop_open_mode_min_change_summary" formatted="false">Алгоритм ИПЖ выдаст всплывающее окно с запросом на новые изменения, только если изменение больше, чем это значение в %. Значение по умолчанию — 20%</string>
|
||||
</resources>
|
||||
|
|
|
@ -27,6 +27,8 @@ dependencies {
|
|||
implementation project(':app-wear-shared:shared')
|
||||
implementation project(':core:interfaces')
|
||||
|
||||
testImplementation project(':implementation')
|
||||
|
||||
api "androidx.constraintlayout:constraintlayout:$constraintlayout_version"
|
||||
api "com.google.android.gms:play-services-location:$play_services_location_version"
|
||||
}
|
|
@ -9,12 +9,12 @@ import info.nightscout.automation.elements.InputString
|
|||
import info.nightscout.automation.elements.LabelWithElement
|
||||
import info.nightscout.automation.elements.LayoutBuilder
|
||||
import info.nightscout.core.extensions.fromConstant
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.database.entities.TherapyEvent
|
||||
import info.nightscout.database.entities.UserEntry
|
||||
import info.nightscout.database.entities.ValueWithUnit
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.database.impl.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.queue.Callback
|
||||
|
|
|
@ -15,8 +15,8 @@ import info.nightscout.automation.events.EventTriggerChanged
|
|||
import info.nightscout.automation.events.EventTriggerClone
|
||||
import info.nightscout.automation.events.EventTriggerRemove
|
||||
import info.nightscout.automation.services.LastLocationDataContainer
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.database.impl.AppRepository
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
|
|
|
@ -7,7 +7,7 @@ import info.nightscout.androidaps.TestBaseWithProfile
|
|||
import info.nightscout.androidaps.TestPumpPlugin
|
||||
import info.nightscout.automation.AutomationPlugin
|
||||
import info.nightscout.automation.services.LastLocationDataContainer
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
|
||||
import info.nightscout.interfaces.aps.AutosensDataStore
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
|
@ -51,7 +51,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
|
|||
it.repository = repository
|
||||
it.activePlugin = activePlugin
|
||||
it.iobCobCalculator = iobCobCalculator
|
||||
it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger, iobCobCalculator, dateUtil)
|
||||
it.glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculator, dateUtil)
|
||||
it.dateUtil = dateUtil
|
||||
}
|
||||
if (it is TriggerBg) {
|
||||
|
|
|
@ -28,6 +28,8 @@ dependencies {
|
|||
implementation project(':core:utils')
|
||||
implementation project(':core:validators')
|
||||
|
||||
testImplementation project(':implementation')
|
||||
|
||||
api "androidx.appcompat:appcompat:$appcompat_version"
|
||||
api "com.google.android.material:material:$material_version"
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ import android.os.Bundle
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.core.extensions.durationInMinutes
|
||||
import info.nightscout.core.extensions.toStringFull
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.receivers.ReceiverStatusStore
|
||||
import info.nightscout.interfaces.Config
|
||||
import info.nightscout.interfaces.aps.Loop
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
|
@ -21,8 +21,8 @@ import info.nightscout.interfaces.plugin.PluginType
|
|||
import info.nightscout.interfaces.profile.DefaultValueHelper
|
||||
import info.nightscout.interfaces.profile.ProfileFunction
|
||||
import info.nightscout.interfaces.receivers.Intents
|
||||
import info.nightscout.interfaces.receivers.ReceiverStatusStore
|
||||
import info.nightscout.plugins.R
|
||||
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.Event
|
||||
|
|
|
@ -31,7 +31,6 @@ import info.nightscout.core.extensions.directionToIcon
|
|||
import info.nightscout.core.extensions.valueToUnitsString
|
||||
import info.nightscout.core.graph.OverviewData
|
||||
import info.nightscout.core.iob.displayText
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.profile.ProfileSealed
|
||||
import info.nightscout.core.ui.UIRunnable
|
||||
import info.nightscout.core.ui.dialogs.OKDialog
|
||||
|
@ -52,6 +51,7 @@ import info.nightscout.interfaces.automation.Automation
|
|||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.nsclient.NSSettingsStatus
|
||||
|
|
|
@ -10,11 +10,11 @@ import dagger.android.HasAndroidInjector
|
|||
import info.nightscout.core.extensions.toStringShort
|
||||
import info.nightscout.core.extensions.valueToUnitsString
|
||||
import info.nightscout.core.iob.generateCOBString
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.interfaces.Constants
|
||||
import info.nightscout.interfaces.NotificationHolder
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
|
|
|
@ -16,7 +16,7 @@ import info.nightscout.shared.utils.DateUtil
|
|||
import info.nightscout.shared.utils.T
|
||||
import javax.inject.Inject
|
||||
|
||||
class AuthRequest internal constructor(
|
||||
class AuthRequest(
|
||||
injector: HasAndroidInjector,
|
||||
var requester: Sms,
|
||||
requestText: String,
|
||||
|
|
|
@ -14,7 +14,6 @@ import info.nightscout.androidaps.annotations.OpenForTesting
|
|||
import info.nightscout.core.events.EventNewNotification
|
||||
import info.nightscout.core.extensions.valueToUnitsString
|
||||
import info.nightscout.core.iob.generateCOBString
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.core.utils.receivers.DataWorkerStorage
|
||||
|
@ -38,6 +37,7 @@ import info.nightscout.interfaces.XDripBroadcast
|
|||
import info.nightscout.interfaces.aps.Loop
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.notifications.Notification
|
||||
|
|
|
@ -9,7 +9,6 @@ import info.nightscout.core.extensions.valueToUnits
|
|||
import info.nightscout.core.extensions.valueToUnitsString
|
||||
import info.nightscout.core.graph.data.GlucoseValueDataPoint
|
||||
import info.nightscout.core.iob.generateCOBString
|
||||
import info.nightscout.core.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.ui.toast.ToastUtils
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
|
@ -34,6 +33,7 @@ import info.nightscout.interfaces.GlucoseUnit
|
|||
import info.nightscout.interfaces.aps.Loop
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.GlucoseStatusProvider
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.logging.UserEntryLogger
|
||||
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.core.graph.OverviewData
|
|||
import info.nightscout.core.iob.combine
|
||||
import info.nightscout.core.iob.copy
|
||||
import info.nightscout.core.iob.determineBasalJson
|
||||
import info.nightscout.core.iob.iobCobCalculator.AutosensDataStoreObject
|
||||
import info.nightscout.core.iob.plus
|
||||
import info.nightscout.core.iob.round
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
|
@ -39,6 +38,7 @@ import info.nightscout.interfaces.profile.ProfileFunction
|
|||
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||
import info.nightscout.interfaces.utils.MidnightTime
|
||||
import info.nightscout.plugins.R
|
||||
import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataStoreObject
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
import info.nightscout.rx.events.Event
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.core.iob.iobCobCalculator
|
||||
package info.nightscout.plugins.iob.iobCobCalculator.data
|
||||
|
||||
import androidx.collection.LongSparseArray
|
||||
import androidx.collection.size
|
||||
|
@ -310,7 +310,9 @@ class AutosensDataStoreObject : AutosensDataStore {
|
|||
val previous = bData[i + 1]
|
||||
val mSecDiff = current.timestamp - previous.timestamp
|
||||
val adjusted = (mSecDiff - T.mins(5).msecs()) / 1000
|
||||
aapsLogger.debug(LTag.AUTOSENS) { "Adjusting bucketed data time. Current: ${dateUtil.dateAndTimeAndSecondsString(current.timestamp)} to: ${dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs())} by $adjusted sec" }
|
||||
aapsLogger.debug(LTag.AUTOSENS) { "Adjusting bucketed data time. Current: ${dateUtil.dateAndTimeAndSecondsString(current.timestamp)} to: ${dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(
|
||||
5
|
||||
).msecs())} by $adjusted sec" }
|
||||
if (abs(adjusted) > 90) {
|
||||
// too big adjustment, fallback to non 5 min data
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Fallback to non 5 min data")
|
||||
|
@ -337,4 +339,4 @@ class AutosensDataStoreObject : AutosensDataStore {
|
|||
}
|
||||
return if (count != 0) sum / count else 0.0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -179,7 +179,6 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
val result = PumpEnactResult(injector)
|
||||
.success(true)
|
||||
.bolusDelivered(detailedBolusInfo.insulin)
|
||||
.carbsDelivered(detailedBolusInfo.carbs)
|
||||
.enacted(detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0)
|
||||
.comment(rh.gs(info.nightscout.core.ui.R.string.virtualpump_resultok))
|
||||
val bolusingEvent = EventOverviewBolusProgress
|
||||
|
|
|
@ -41,17 +41,11 @@ class AidexPlugin @Inject constructor(
|
|||
aapsLogger, rh, injector
|
||||
), BgSource {
|
||||
|
||||
private var advancedFiltering = false
|
||||
|
||||
/**
|
||||
* Aidex App doesn't have upload to NS
|
||||
*/
|
||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = true
|
||||
|
||||
override fun advancedFilteringSupported(): Boolean {
|
||||
return advancedFiltering
|
||||
}
|
||||
|
||||
// Allow only for pumpcontrol or dev & engineering_mode
|
||||
override fun specialEnableCondition(): Boolean {
|
||||
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.profile.Profile
|
||||
import info.nightscout.interfaces.source.BgSource
|
||||
import info.nightscout.interfaces.source.DexcomBoyda
|
||||
import info.nightscout.plugins.R
|
||||
import info.nightscout.plugins.source.activities.RequestDexcomPermissionActivity
|
||||
import info.nightscout.rx.logging.AAPSLogger
|
||||
|
@ -58,7 +59,7 @@ class DexcomPlugin @Inject constructor(
|
|||
.preferencesId(R.xml.pref_dexcom)
|
||||
.description(R.string.description_source_dexcom),
|
||||
aapsLogger, rh, injector
|
||||
), BgSource {
|
||||
), BgSource, DexcomBoyda {
|
||||
|
||||
init {
|
||||
if (!config.NSCLIENT) {
|
||||
|
@ -66,9 +67,7 @@ class DexcomPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun advancedFilteringSupported(): Boolean {
|
||||
return true
|
||||
}
|
||||
override fun advancedFilteringSupported(): Boolean = true
|
||||
|
||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
||||
(glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE ||
|
||||
|
|
|
@ -64,9 +64,7 @@ class NSClientSourcePlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun advancedFilteringSupported(): Boolean {
|
||||
return isAdvancedFilteringEnabled
|
||||
}
|
||||
override fun advancedFilteringSupported(): Boolean = isAdvancedFilteringEnabled
|
||||
|
||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
|
||||
|
||||
|
|
|
@ -73,9 +73,7 @@ class RandomBgPlugin @Inject constructor(
|
|||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun advancedFilteringSupported(): Boolean {
|
||||
return true
|
||||
}
|
||||
override fun advancedFilteringSupported(): Boolean = true
|
||||
|
||||
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean =
|
||||
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 advancedFilteringSupported(): Boolean {
|
||||
return advancedFiltering
|
||||
}
|
||||
override fun advancedFilteringSupported(): Boolean = advancedFiltering
|
||||
|
||||
private fun detectSource(glucoseValue: GlucoseValue) {
|
||||
advancedFiltering = arrayOf(
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -7,9 +7,11 @@ import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
|||
import info.nightscout.interfaces.constraints.Constraint
|
||||
import info.nightscout.interfaces.constraints.Constraints
|
||||
import info.nightscout.interfaces.iob.IobCobCalculator
|
||||
import info.nightscout.interfaces.plugin.ActivePlugin
|
||||
import info.nightscout.interfaces.plugin.PluginBase
|
||||
import info.nightscout.interfaces.plugin.PluginDescription
|
||||
import info.nightscout.interfaces.plugin.PluginType
|
||||
import info.nightscout.interfaces.source.DexcomBoyda
|
||||
import info.nightscout.plugins.support.R
|
||||
import info.nightscout.rx.AapsSchedulers
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
|
@ -24,6 +26,7 @@ import io.reactivex.rxjava3.kotlin.plusAssign
|
|||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@Singleton
|
||||
|
@ -33,10 +36,11 @@ class BgQualityCheckPlugin @Inject constructor(
|
|||
rh: ResourceHelper,
|
||||
private val rxBus: RxBus,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val aapsSchedulers:
|
||||
private val aapsSchedulers:
|
||||
AapsSchedulers,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val dateUtil: DateUtil
|
||||
private val dateUtil: DateUtil,
|
||||
private val activePlugin: ActivePlugin
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.CONSTRAINTS)
|
||||
|
@ -49,13 +53,6 @@ class BgQualityCheckPlugin @Inject constructor(
|
|||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
enum class State {
|
||||
UNKNOWN,
|
||||
FIVE_MIN_DATA,
|
||||
RECALCULATED,
|
||||
DOUBLED
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
disposable += rxBus
|
||||
|
@ -69,51 +66,87 @@ class BgQualityCheckPlugin @Inject constructor(
|
|||
disposable.clear()
|
||||
}
|
||||
|
||||
var state: State = State.UNKNOWN
|
||||
override var state: BgQualityCheck.State = BgQualityCheck.State.UNKNOWN
|
||||
override var message: String = ""
|
||||
|
||||
// Fallback to LGS if BG values are doubled
|
||||
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)
|
||||
else
|
||||
maxIob
|
||||
|
||||
@Suppress("CascadeIf") fun processBgData() {
|
||||
fun processBgData() {
|
||||
val readings = iobCobCalculator.ads.getBgReadingsDataTableCopy()
|
||||
for (i in readings.indices)
|
||||
// Deltas are calculated from last ~50 min. Detect RED state only on this interval
|
||||
if (i < min(readings.size - 2, 10))
|
||||
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]}")
|
||||
message = rh.gs(R.string.bg_too_close, dateUtil.dateAndTimeAndSecondsString(readings[i].timestamp), dateUtil.dateAndTimeAndSecondsString(readings[i + 1].timestamp))
|
||||
return
|
||||
}
|
||||
if (iobCobCalculator.ads.lastUsed5minCalculation == true) {
|
||||
state = State.FIVE_MIN_DATA
|
||||
if (activePlugin.activeBgSource !is DexcomBoyda && isBgFlatForInterval(staleBgCheckPeriodMinutes, staleBgMaxDeltaMgdl) == true) {
|
||||
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"
|
||||
} else if (iobCobCalculator.ads.lastUsed5minCalculation == false) {
|
||||
state = State.RECALCULATED
|
||||
state = BgQualityCheck.State.RECALCULATED
|
||||
message = rh.gs(R.string.recalculated_data_used)
|
||||
} else {
|
||||
state = State.UNKNOWN
|
||||
state = BgQualityCheck.State.UNKNOWN
|
||||
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
|
||||
|
||||
var bgmin: Double = lastBg
|
||||
var bgmax: Double = bgmin
|
||||
for (bg in data) {
|
||||
if (bg.timestamp < offset) break
|
||||
bgmin = min(bgmin, bg.value)
|
||||
bgmax = max(bgmax, bg.value)
|
||||
if (bgmax - bgmin > maxDelta) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@DrawableRes override 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
|
||||
BgQualityCheck.State.UNKNOWN -> 0
|
||||
BgQualityCheck.State.FIVE_MIN_DATA -> 0
|
||||
BgQualityCheck.State.RECALCULATED -> R.drawable.ic_baseline_warning_24_yellow
|
||||
BgQualityCheck.State.DOUBLED -> R.drawable.ic_baseline_warning_24_red
|
||||
BgQualityCheck.State.FLAT -> R.drawable.ic_baseline_trending_flat_24
|
||||
}
|
||||
|
||||
override fun stateDescription(): String =
|
||||
when (state) {
|
||||
State.RECALCULATED -> rh.gs(R.string.a11y_bg_quality_recalculated)
|
||||
State.DOUBLED -> rh.gs(R.string.a11y_bg_quality_doubles)
|
||||
else -> ""
|
||||
BgQualityCheck.State.RECALCULATED -> rh.gs(R.string.a11y_bg_quality_recalculated)
|
||||
BgQualityCheck.State.DOUBLED -> rh.gs(R.string.a11y_bg_quality_doubles)
|
||||
BgQualityCheck.State.FLAT -> rh.gs(R.string.a11y_bg_quality_flat)
|
||||
else -> ""
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val staleBgCheckPeriodMinutes = 45L
|
||||
const val staleBgMaxDeltaMgdl = 2.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>
|
|
@ -20,4 +20,5 @@
|
|||
<string name="bg_too_close">BS for nær:\n%1$s\n%2$s</string>
|
||||
<string name="a11y_bg_quality_recalculated">beregnet på nytt</string>
|
||||
<string name="a11y_bg_quality_doubles">doble registreringer</string>
|
||||
<string name="a11y_bg_quality_flat">Flate verdier. Vurderer dette til å være feil</string>
|
||||
</resources>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<string name="dst_in_24h_warning">Переход на летнее/зимнее время через 24 часа или менее</string>
|
||||
<string name="dst_loop_disabled_warning">Изменение сезонного времени произошло меньше 3 часов назад-Закрытый цикл выключен</string>
|
||||
<!-- Storage constraint -->
|
||||
<string name="disk_full">Освободите по крайней мере %1$d MB из внутренней памяти! Цикл остановлен!</string>
|
||||
<!-- Version Checker -->
|
||||
<string name="old_version">старая версия</string>
|
||||
<string name="very_old_version">очень старая версия</string>
|
||||
|
|
|
@ -39,5 +39,6 @@
|
|||
<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_doubles">double entries</string>
|
||||
<string name="a11y_bg_quality_flat">Flat data. Considered to be wrong</string>
|
||||
|
||||
</resources>
|
|
@ -6,14 +6,18 @@ import info.nightscout.androidaps.TestBase
|
|||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.database.entities.GlucoseValue
|
||||
import info.nightscout.interfaces.aps.AutosensDataStore
|
||||
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
|
||||
import info.nightscout.interfaces.constraints.Constraint
|
||||
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.rx.bus.RxBus
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.utils.DateUtil
|
||||
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.Test
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
|
@ -28,10 +32,12 @@ class BgQualityCheckPluginTest : TestBase() {
|
|||
@Mock lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Mock lateinit var dateUtil: DateUtil
|
||||
@Mock lateinit var autosensDataStore: AutosensDataStore
|
||||
@Mock lateinit var activePlugin: ActivePlugin
|
||||
|
||||
private lateinit var plugin: BgQualityCheckPlugin
|
||||
|
||||
val injector = HasAndroidInjector { AndroidInjector { } }
|
||||
private val injector = HasAndroidInjector { AndroidInjector { } }
|
||||
val now = 100000000L
|
||||
//private val autosensDataStore = AutosensDataStoreObject()
|
||||
|
||||
@BeforeEach
|
||||
|
@ -45,27 +51,29 @@ class BgQualityCheckPluginTest : TestBase() {
|
|||
iobCobCalculator,
|
||||
aapsSchedulers,
|
||||
fabricPrivacy,
|
||||
dateUtil
|
||||
dateUtil,
|
||||
activePlugin
|
||||
)
|
||||
`when`(iobCobCalculator.ads).thenReturn(autosensDataStore)
|
||||
`when`(rh.gs(anyInt())).thenReturn("")
|
||||
`when`(rh.gs(anyInt(), any(), any())).thenReturn("")
|
||||
`when`(dateUtil.now()).thenReturn(now)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun runTest() {
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(null)
|
||||
plugin.processBgData()
|
||||
Assert.assertEquals(BgQualityCheckPlugin.State.UNKNOWN, plugin.state)
|
||||
Assert.assertEquals(0, plugin.icon())
|
||||
Assertions.assertEquals(BgQualityCheck.State.UNKNOWN, plugin.state)
|
||||
Assertions.assertEquals(0, plugin.icon())
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||
plugin.processBgData()
|
||||
Assert.assertEquals(BgQualityCheckPlugin.State.FIVE_MIN_DATA, plugin.state)
|
||||
Assert.assertEquals(0, plugin.icon())
|
||||
Assertions.assertEquals(BgQualityCheck.State.FIVE_MIN_DATA, plugin.state)
|
||||
Assertions.assertEquals(0, plugin.icon())
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
||||
plugin.processBgData()
|
||||
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
||||
Assert.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon())
|
||||
Assertions.assertEquals(BgQualityCheck.State.RECALCULATED, plugin.state)
|
||||
Assertions.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))
|
||||
|
@ -76,10 +84,10 @@ class BgQualityCheckPluginTest : TestBase() {
|
|||
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||
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)
|
||||
plugin.processBgData()
|
||||
Assert.assertEquals(BgQualityCheckPlugin.State.RECALCULATED, plugin.state)
|
||||
Assertions.assertEquals(BgQualityCheck.State.RECALCULATED, plugin.state)
|
||||
|
||||
val duplicatedData: MutableList<GlucoseValue> = ArrayList()
|
||||
duplicatedData.add(
|
||||
|
@ -136,8 +144,8 @@ class BgQualityCheckPluginTest : TestBase() {
|
|||
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
|
||||
plugin.processBgData()
|
||||
Assert.assertEquals(BgQualityCheckPlugin.State.DOUBLED, plugin.state)
|
||||
Assert.assertEquals(R.drawable.ic_baseline_warning_24_red, plugin.icon())
|
||||
Assertions.assertEquals(BgQualityCheck.State.DOUBLED, plugin.state)
|
||||
Assertions.assertEquals(R.drawable.ic_baseline_warning_24_red, plugin.icon())
|
||||
|
||||
val identicalData: MutableList<GlucoseValue> = ArrayList()
|
||||
identicalData.add(
|
||||
|
@ -194,19 +202,73 @@ class BgQualityCheckPluginTest : TestBase() {
|
|||
|
||||
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(false)
|
||||
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
|
||||
fun applyMaxIOBConstraintsTest() {
|
||||
plugin.state = BgQualityCheckPlugin.State.UNKNOWN
|
||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheckPlugin.State.FIVE_MIN_DATA
|
||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheckPlugin.State.RECALCULATED
|
||||
Assert.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheckPlugin.State.DOUBLED
|
||||
Assert.assertEquals(0.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheck.State.UNKNOWN
|
||||
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheck.State.FIVE_MIN_DATA
|
||||
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheck.State.RECALCULATED
|
||||
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
plugin.state = BgQualityCheck.State.DOUBLED
|
||||
Assertions.assertEquals(0.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
|
||||
}
|
||||
|
||||
}
|
|
@ -28,7 +28,7 @@ dependencies {
|
|||
|
||||
|
||||
// NSClient, Tidepool
|
||||
api("io.socket:socket.io-client:1.0.0") {
|
||||
api("io.socket:socket.io-client:1.0.2") {
|
||||
// excluding org.json which is provided by Android
|
||||
exclude group: "org.json", module: "json"
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
SystemClock.sleep(pause)
|
||||
|
||||
if (carbs.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsCarbsTransaction(carbs))
|
||||
repository.runTransactionForResult(SyncNsCarbsTransaction(carbs, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
SystemClock.sleep(pause)
|
||||
|
||||
if (temporaryTargets.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTargets))
|
||||
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTargets, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
SystemClock.sleep(pause)
|
||||
|
||||
if (temporaryBasals.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasals))
|
||||
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasals, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
if (therapyEvents.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvents))
|
||||
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvents, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
SystemClock.sleep(pause)
|
||||
|
||||
if (offlineEvents.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvents))
|
||||
repository.runTransactionForResult(SyncNsOfflineEventTransaction(offlineEvents, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
}
|
||||
|
@ -653,7 +653,7 @@ class StoreDataForDbImpl @Inject constructor(
|
|||
SystemClock.sleep(pause)
|
||||
|
||||
if (extendedBoluses.isNotEmpty())
|
||||
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBoluses))
|
||||
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBoluses, config.NSCLIENT))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,5 @@ fun PumpEnactResult.log(): String {
|
|||
" IsPercent: " + isPercent +
|
||||
" IsTempCancel: " + isTempCancel +
|
||||
" bolusDelivered: " + bolusDelivered +
|
||||
" carbsDelivered: " + carbsDelivered +
|
||||
" Queued: " + queued
|
||||
}
|
|
@ -629,8 +629,7 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
|
|||
return new PumpEnactResult(getInjector())
|
||||
.success(true)
|
||||
.enacted(lastPumpBolus.amount > 0)
|
||||
.bolusDelivered(lastPumpBolus.amount)
|
||||
.carbsDelivered(detailedBolusInfo.carbs);
|
||||
.bolusDelivered(lastPumpBolus.amount);
|
||||
} finally {
|
||||
pump.activity = null;
|
||||
rxBus.send(new EventComboPumpUpdateGUI());
|
||||
|
|
|
@ -16,6 +16,7 @@ dependencies {
|
|||
implementation project(':core:utils')
|
||||
implementation project(':app-wear-shared:shared')
|
||||
implementation(project(":pump:combov2:comboctl"))
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:$kotlinx_datetime_version")
|
||||
// This is necessary to avoid errors like these which otherwise come up often at runtime:
|
||||
// "WARNING: Failed to transform class kotlinx/datetime/TimeZone$Companion
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'com.hiya.jacoco-android'
|
||||
}
|
||||
|
||||
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/android_module_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
|
||||
|
||||
android {
|
||||
namespace 'info.nightscout.comboctl'
|
||||
|
@ -10,6 +17,9 @@ android {
|
|||
kotlin.srcDirs += ['src/commonMain/kotlin', 'src/androidMain/kotlin']
|
||||
manifest.srcFile 'src/androidMain/AndroidManifest.xml'
|
||||
}
|
||||
test {
|
||||
kotlin.srcDirs += ['src/jvmTest/kotlin']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,4 +28,8 @@ dependencies {
|
|||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-datetime:$kotlinx_datetime_version"
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
}
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-test'
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version"
|
||||
}
|
|
@ -1166,6 +1166,19 @@ class Pump(
|
|||
*/
|
||||
val setTbrProgressFlow = setTbrProgressReporter.progressFlow
|
||||
|
||||
/**
|
||||
* Detail about the outcome of a successful [setTbr] call.
|
||||
*
|
||||
* Note that all of these describe a success. In case of failure,
|
||||
* [setTbr] throws an exception.
|
||||
*/
|
||||
enum class SetTbrOutcome {
|
||||
SET_NORMAL_TBR,
|
||||
SET_EMULATED_100_TBR,
|
||||
LETTING_EMULATED_100_TBR_FINISH,
|
||||
IGNORED_REDUNDANT_100_TBR
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Combo's current temporary basal rate (TBR) via the remote terminal (RT) mode.
|
||||
*
|
||||
|
@ -1199,6 +1212,9 @@ class Pump(
|
|||
* via the [onEvent] callback. Likewise, when a TBR finishes or is cancelled,
|
||||
* [Event.TbrEnded] is emitted.
|
||||
*
|
||||
* When this function finishes successfully, it informs about the exact
|
||||
* outcome through its return value.
|
||||
*
|
||||
* @param percentage TBR percentage to set.
|
||||
* @param durationInMinutes TBR duration in minutes to set.
|
||||
* This argument is not used if [percentage] is 100.
|
||||
|
@ -1209,6 +1225,7 @@ class Pump(
|
|||
* cancelling an ongoing TBR, which produces a W6 warning) or to fake a
|
||||
* 100% TBR by setting 90% / 110% TBRs (see above).
|
||||
* This argument is only used if [percentage] is 100.
|
||||
* @return The specific outcome if setting the TBR succeeds.
|
||||
* @throws IllegalArgumentException if the percentage is not in the 0-500 range,
|
||||
* or if the percentage value is not an integer multiple of 10, or if
|
||||
* the duration is <15 or not an integer multiple of 15 (see the note
|
||||
|
@ -1244,6 +1261,7 @@ class Pump(
|
|||
val currentStatus = statusFlow.value ?: throw IllegalStateException("Cannot start TBR without a known pump status")
|
||||
var expectedTbrPercentage: Int
|
||||
var expectedTbrDuration: Int
|
||||
val result: SetTbrOutcome
|
||||
|
||||
// In the code below, we always create a Tbr object _before_ calling
|
||||
// setCurrentTbr to make use of the checks in the Tbr constructor.
|
||||
|
@ -1258,6 +1276,20 @@ class Pump(
|
|||
reportOngoingTbrAsStopped()
|
||||
expectedTbrPercentage = 100
|
||||
expectedTbrDuration = 0
|
||||
result = SetTbrOutcome.SET_NORMAL_TBR
|
||||
} else if ((currentStatus.tbrPercentage in 90..110) && (currentStatus.remainingTbrDurationInMinutes <= 15)) {
|
||||
// If the current TBR is in the 90-110% range, it is pretty much a fake 100% TBR.
|
||||
// So, if that fake TBR is done within 15 minutes, we don't actually set anything.
|
||||
// Instead, we just let it run. That way, the pump can actually reach 100% TBR,
|
||||
// and the amount of TBR adjustments is reduced.
|
||||
expectedTbrPercentage = currentStatus.tbrPercentage
|
||||
expectedTbrDuration = currentStatus.remainingTbrDurationInMinutes
|
||||
result = SetTbrOutcome.LETTING_EMULATED_100_TBR_FINISH
|
||||
logger(LogLevel.INFO) {
|
||||
"Current TBR percentage is in the 90-110% range (${currentStatus.tbrPercentage}%)," +
|
||||
"and it will finish in ${currentStatus.remainingTbrDurationInMinutes} minute(s); " +
|
||||
"letting it finish and faking a successful TBR set operation"
|
||||
}
|
||||
} else {
|
||||
val newPercentage = if (currentStatus.tbrPercentage < 100) 110 else 90
|
||||
val tbr = Tbr(
|
||||
|
@ -1270,6 +1302,7 @@ class Pump(
|
|||
reportStartedTbr(tbr)
|
||||
expectedTbrPercentage = newPercentage
|
||||
expectedTbrDuration = 15
|
||||
result = SetTbrOutcome.SET_EMULATED_100_TBR
|
||||
}
|
||||
} else {
|
||||
// Current status shows that there is no TBR ongoing. This is
|
||||
|
@ -1278,6 +1311,7 @@ class Pump(
|
|||
expectedTbrPercentage = 100
|
||||
expectedTbrDuration = 0
|
||||
logger(LogLevel.INFO) { "TBR was already cancelled" }
|
||||
result = SetTbrOutcome.IGNORED_REDUNDANT_100_TBR
|
||||
}
|
||||
} else {
|
||||
val tbr = Tbr(
|
||||
|
@ -1291,6 +1325,7 @@ class Pump(
|
|||
reportStartedTbr(tbr)
|
||||
expectedTbrPercentage = percentage
|
||||
expectedTbrDuration = durationInMinutes
|
||||
result = SetTbrOutcome.SET_NORMAL_TBR
|
||||
}
|
||||
|
||||
// We just set the TBR. Now check the main screen contents to see if
|
||||
|
@ -1314,9 +1349,12 @@ class Pump(
|
|||
throw ExtendedOrMultiwaveBolusActiveException(mainScreenContent)
|
||||
|
||||
is MainScreenContent.Normal -> {
|
||||
if (expectedTbrPercentage != 100) {
|
||||
if ((expectedTbrPercentage != 100) && (expectedTbrDuration >= 2)) {
|
||||
// We expected a TBR to be active, but there isn't any;
|
||||
// we aren't seen any TBR main screen contents.
|
||||
// Only consider this an error if the duration is >2 minutes.
|
||||
// Otherwise, this was a TBR that was about to end, so it
|
||||
// might have ended while these checks here were running.
|
||||
throw UnexpectedTbrStateException(
|
||||
expectedTbrPercentage = expectedTbrPercentage,
|
||||
expectedTbrDuration = expectedTbrDuration,
|
||||
|
@ -1349,6 +1387,8 @@ class Pump(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@executeCommand result
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
package info.nightscout.pump.combov2
|
||||
|
||||
import info.nightscout.comboctl.base.BluetoothAddress
|
||||
import info.nightscout.comboctl.base.CurrentTbrState
|
||||
import info.nightscout.comboctl.base.InvariantPumpData
|
||||
import info.nightscout.comboctl.base.Nonce
|
||||
import info.nightscout.comboctl.base.PumpStateStore
|
||||
import info.nightscout.comboctl.base.Tbr
|
||||
import info.nightscout.comboctl.base.toBluetoothAddress
|
||||
import info.nightscout.comboctl.base.toCipher
|
||||
import info.nightscout.comboctl.base.toNonce
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateInt
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateLong
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateString
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.UtcOffset
|
||||
import kotlin.reflect.KClassifier
|
||||
|
||||
/**
|
||||
* Special pump state store that mainly uses the internalSP, but also is able to sync up the AAPS main SP with that internal SP.
|
||||
*
|
||||
* This pump state store solves a problem: What if the user already paired AAPS with a Combo, and then imports and old AAPS
|
||||
* settings file, intending to just restore other settings like the basal profile, but does _not_ intend to import an old
|
||||
* pump state? After all, if we write a pump state to the AAPS main SP, the state values will also be written into a settings
|
||||
* file when exporting said settings. If we just relied on the main AAPS SP, the current pump state - including pairing info
|
||||
* like the PC and CP keys - would be overwritten with the old ones from the imported settings, and the user would have to
|
||||
* unnecessarily re-pair the Combo every time settings get imported.
|
||||
*
|
||||
* The solution is for this driver to _not_ primarily use the AAPS main SP. Instead, it uses its own internal SP. That SP
|
||||
* is exclusively used by this driver. But, a copy of the pump state values are stored in the AAPS main SP, and kept in
|
||||
* sync with the contents of the internal SP.
|
||||
*
|
||||
* When a new pump state is created, the invariant values (CP/PC keys etc.) are written in both the AAPS main SP and the
|
||||
* internal SP, along with the initial nonce. During operation, the driver will update the nonce value of the internal SP.
|
||||
* If TBR states are changed, then these changes are stored in the internal SP. Callers can use [copyVariantValuesToAAPSMainSP]
|
||||
* to update the corresponding values in the AAPS main SP to keep the two SPs in sync.
|
||||
*
|
||||
* There are a couple of special situations:
|
||||
*
|
||||
* 1. There is no pump state in the internal SP, and there is no pump state in the AAPS main SP. This is the unpaired state.
|
||||
* 2. There is no pump state in the internal SP, but there is one in the AAPS main SP. This typically happens when the
|
||||
* user (re)installed AAPS, and immediately after installing, imported AAPS settings. Callers are then supposed to call
|
||||
* [copyAllValuesFromAAPSMainSP] to import the pump state from the AAPS main SP over to the internal SP and continue to
|
||||
* work with that state.
|
||||
* 3. There is a pump state, and there is also one in the AAPS main SP. The latter one is then ignored. A pump state in the
|
||||
* AAPS main SP solely and only exists to be able to export/import pump states. It is not used for actual pump operations.
|
||||
* In particular, if - as mentioned above - a pump is already paired, and the user imports settings, this logic prevents
|
||||
* the current pump state to be overwritten.
|
||||
*/
|
||||
class AAPSPumpStateStore(
|
||||
private val aapsMainSP: SP,
|
||||
private val internalSP: InternalSP
|
||||
) : PumpStateStore {
|
||||
private var btAddress: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.BT_ADDRESS_KEY.str, "")
|
||||
|
||||
// The nonce is updated with commit instead of apply to make sure
|
||||
// is atomically written to storage synchronously, minimizing
|
||||
// the likelihood that it could be lost due to app crashes etc.
|
||||
// It is very important to not lose the nonce, hence that choice.
|
||||
private var nonceString: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.NONCE_KEY.str, Nonce.nullNonce().toString(), commit = true)
|
||||
|
||||
private var cpCipherString: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.CP_CIPHER_KEY.str, "")
|
||||
private var pcCipherString: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.PC_CIPHER_KEY.str, "")
|
||||
private var keyResponseAddressInt: Int
|
||||
by SPDelegateInt(internalSP, PreferenceKeys.KEY_RESPONSE_ADDRESS_KEY.str, 0)
|
||||
private var pumpID: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.PUMP_ID_KEY.str, "")
|
||||
private var tbrTimestamp: Long
|
||||
by SPDelegateLong(internalSP, PreferenceKeys.TBR_TIMESTAMP_KEY.str, 0)
|
||||
private var tbrPercentage: Int
|
||||
by SPDelegateInt(internalSP, PreferenceKeys.TBR_PERCENTAGE_KEY.str, 0)
|
||||
private var tbrDuration: Int
|
||||
by SPDelegateInt(internalSP, PreferenceKeys.TBR_DURATION_KEY.str, 0)
|
||||
private var tbrType: String
|
||||
by SPDelegateString(internalSP, PreferenceKeys.TBR_TYPE_KEY.str, "")
|
||||
private var utcOffsetSeconds: Int
|
||||
by SPDelegateInt(internalSP, PreferenceKeys.UTC_OFFSET_KEY.str, 0)
|
||||
|
||||
override fun createPumpState(
|
||||
pumpAddress: BluetoothAddress,
|
||||
invariantPumpData: InvariantPumpData,
|
||||
utcOffset: UtcOffset,
|
||||
tbrState: CurrentTbrState
|
||||
) {
|
||||
internalSP.edit(commit = true) {
|
||||
putString(PreferenceKeys.BT_ADDRESS_KEY.str, pumpAddress.toString().uppercase())
|
||||
putString(PreferenceKeys.CP_CIPHER_KEY.str, invariantPumpData.clientPumpCipher.toString())
|
||||
putString(PreferenceKeys.PC_CIPHER_KEY.str, invariantPumpData.pumpClientCipher.toString())
|
||||
putInt(PreferenceKeys.KEY_RESPONSE_ADDRESS_KEY.str, invariantPumpData.keyResponseAddress.toInt() and 0xFF)
|
||||
putString(PreferenceKeys.PUMP_ID_KEY.str, invariantPumpData.pumpID)
|
||||
putLong(PreferenceKeys.TBR_TIMESTAMP_KEY.str, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.timestamp.epochSeconds else -1)
|
||||
putInt(PreferenceKeys.TBR_PERCENTAGE_KEY.str, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.percentage else -1)
|
||||
putInt(PreferenceKeys.TBR_DURATION_KEY.str, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.durationInMinutes else -1)
|
||||
putString(PreferenceKeys.TBR_TYPE_KEY.str, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.type.stringId else "")
|
||||
putInt(PreferenceKeys.UTC_OFFSET_KEY.str, utcOffset.totalSeconds)
|
||||
}
|
||||
|
||||
copyAllValuesToAAPSMainSP(commit = true)
|
||||
}
|
||||
|
||||
override fun deletePumpState(pumpAddress: BluetoothAddress): Boolean {
|
||||
val hasState = internalSP.contains(PreferenceKeys.NONCE_KEY.str)
|
||||
|
||||
internalSP.edit(commit = true) {
|
||||
for (keys in PreferenceKeys.values())
|
||||
remove(keys.str)
|
||||
}
|
||||
|
||||
aapsMainSP.edit(commit = true) {
|
||||
for (keys in PreferenceKeys.values())
|
||||
remove(keys.str)
|
||||
}
|
||||
|
||||
return hasState
|
||||
}
|
||||
|
||||
override fun hasPumpState(pumpAddress: BluetoothAddress): Boolean =
|
||||
internalSP.contains(PreferenceKeys.NONCE_KEY.str)
|
||||
|
||||
override fun getAvailablePumpStateAddresses(): Set<BluetoothAddress> =
|
||||
if (btAddress.isBlank()) setOf() else setOf(btAddress.toBluetoothAddress())
|
||||
|
||||
override fun getInvariantPumpData(pumpAddress: BluetoothAddress) = InvariantPumpData(
|
||||
clientPumpCipher = cpCipherString.toCipher(),
|
||||
pumpClientCipher = pcCipherString.toCipher(),
|
||||
keyResponseAddress = keyResponseAddressInt.toByte(),
|
||||
pumpID = pumpID
|
||||
)
|
||||
|
||||
override fun getCurrentTxNonce(pumpAddress: BluetoothAddress) = nonceString.toNonce()
|
||||
|
||||
override fun setCurrentTxNonce(pumpAddress: BluetoothAddress, currentTxNonce: Nonce) {
|
||||
nonceString = currentTxNonce.toString()
|
||||
}
|
||||
|
||||
override fun getCurrentUtcOffset(pumpAddress: BluetoothAddress) =
|
||||
UtcOffset(seconds = utcOffsetSeconds)
|
||||
|
||||
override fun setCurrentUtcOffset(pumpAddress: BluetoothAddress, utcOffset: UtcOffset) {
|
||||
utcOffsetSeconds = utcOffset.totalSeconds
|
||||
}
|
||||
|
||||
override fun getCurrentTbrState(pumpAddress: BluetoothAddress) =
|
||||
if (tbrTimestamp >= 0)
|
||||
CurrentTbrState.TbrStarted(Tbr(
|
||||
timestamp = Instant.fromEpochSeconds(tbrTimestamp),
|
||||
percentage = tbrPercentage,
|
||||
durationInMinutes = tbrDuration,
|
||||
type = Tbr.Type.fromStringId(tbrType)!!
|
||||
))
|
||||
else
|
||||
CurrentTbrState.NoTbrOngoing
|
||||
|
||||
|
||||
override fun setCurrentTbrState(pumpAddress: BluetoothAddress, currentTbrState: CurrentTbrState) {
|
||||
when (currentTbrState) {
|
||||
is CurrentTbrState.TbrStarted -> {
|
||||
tbrTimestamp = currentTbrState.tbr.timestamp.epochSeconds
|
||||
tbrPercentage = currentTbrState.tbr.percentage
|
||||
tbrDuration = currentTbrState.tbr.durationInMinutes
|
||||
tbrType = currentTbrState.tbr.type.stringId
|
||||
}
|
||||
else -> {
|
||||
tbrTimestamp = -1
|
||||
tbrPercentage = -1
|
||||
tbrDuration = -1
|
||||
tbrType = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copies only those pump state values from the internal SP to the AAPS main SP which can vary during
|
||||
// pump operations. These are the TBR values, the UTC offset, and the nonce. Users are recommended to
|
||||
// call this after AAPS disconnects the pump.
|
||||
fun copyVariantValuesToAAPSMainSP(commit: Boolean) =
|
||||
copyValuesBetweenSPs(commit, from = internalSP, to = aapsMainSP, arrayOf(
|
||||
PreferenceKeys.NONCE_KEY,
|
||||
PreferenceKeys.TBR_TIMESTAMP_KEY,
|
||||
PreferenceKeys.TBR_PERCENTAGE_KEY,
|
||||
PreferenceKeys.TBR_DURATION_KEY,
|
||||
PreferenceKeys.TBR_TYPE_KEY,
|
||||
PreferenceKeys.UTC_OFFSET_KEY
|
||||
))
|
||||
|
||||
// Copies all pump state values from the AAPS main SP to the internal SP. This is supposed to be
|
||||
// called if the internal SP is empty. That way, a pump state can be imported from AAPS settings files.
|
||||
fun copyAllValuesFromAAPSMainSP(commit: Boolean) =
|
||||
copyValuesBetweenSPs(commit, from = aapsMainSP, to = internalSP, keys = PreferenceKeys.values())
|
||||
|
||||
// Copies all pump state values from the internal SP to the AAPS main SP to. The createPumpState()
|
||||
// function calls this after creating the pump state to ensure both SPs are in sync. Also, this
|
||||
// should be called when the driver starts in case AAPS settings are imported and there is already
|
||||
// a pump state present in the internal SP. Calling this then ensures that the pump state in the
|
||||
// main SP is fully synced up with the one from the internal SP, and does not contain some old
|
||||
// state that is not in use anymore.
|
||||
fun copyAllValuesToAAPSMainSP(commit: Boolean) =
|
||||
copyValuesBetweenSPs(commit, from = internalSP, to = aapsMainSP, keys = PreferenceKeys.values())
|
||||
|
||||
private fun copyValuesBetweenSPs(commit: Boolean, from: SP, to: SP, keys: Array<PreferenceKeys>) {
|
||||
to.edit(commit) {
|
||||
for (key in keys) {
|
||||
if (!from.contains(key.str))
|
||||
continue
|
||||
when (key.type) {
|
||||
Int::class -> putInt(key.str, from.getInt(key.str, 0))
|
||||
Long::class -> putLong(key.str, from.getLong(key.str, 0L))
|
||||
String::class -> putString(key.str, from.getString(key.str, ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class PreferenceKeys(val str: String, val type: KClassifier) {
|
||||
BT_ADDRESS_KEY("combov2-bt-address-key", String::class),
|
||||
NONCE_KEY("combov2-nonce-key", String::class),
|
||||
CP_CIPHER_KEY("combov2-cp-cipher-key", String::class),
|
||||
PC_CIPHER_KEY("combov2-pc-cipher-key", String::class),
|
||||
KEY_RESPONSE_ADDRESS_KEY("combov2-key-response-address-key", Int::class),
|
||||
PUMP_ID_KEY("combov2-pump-id-key", String::class),
|
||||
TBR_TIMESTAMP_KEY("combov2-tbr-timestamp", Long::class),
|
||||
TBR_PERCENTAGE_KEY("combov2-tbr-percentage", Int::class),
|
||||
TBR_DURATION_KEY("combov2-tbr-duration", Int::class),
|
||||
TBR_TYPE_KEY("combov2-tbr-type", String::class),
|
||||
UTC_OFFSET_KEY("combov2-utc-offset", Int::class);
|
||||
|
||||
override fun toString(): String = str
|
||||
}
|
||||
}
|
|
@ -133,7 +133,17 @@ class ComboV2Plugin @Inject constructor (
|
|||
|
||||
private val _pumpDescription = PumpDescription()
|
||||
|
||||
private val pumpStateStore = SPPumpStateStore(sp)
|
||||
// The internal SP is the one that will be mainly used by the driver.
|
||||
// The AAPS main SP is updated when the pump state store is created
|
||||
// and when the driver disconnects (to update the nonce value).
|
||||
private val internalSP = InternalSP(
|
||||
context.getSharedPreferences(
|
||||
context.packageName + ".COMBO_PUMP_STATE_STORE",
|
||||
Context.MODE_PRIVATE
|
||||
),
|
||||
context
|
||||
)
|
||||
private val pumpStateStore = AAPSPumpStateStore(aapsMainSP = sp, internalSP = internalSP)
|
||||
|
||||
// These are initialized in onStart() and torn down in onStop().
|
||||
private var bluetoothInterface: AndroidBluetoothInterface? = null
|
||||
|
@ -236,6 +246,34 @@ class ComboV2Plugin @Inject constructor (
|
|||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
// Check if there is a pump state in the internal SP. If not, try to
|
||||
// copy a pump state from the AAPS main SP. It is possible for example
|
||||
// that AAPS was reinstalled, and the previous settings were imported.
|
||||
// In that case, the internal SP is empty, but there is a pump state
|
||||
// that comes from the settings. We want to restore that pump state
|
||||
// then. If however, there _is_ a pump state in the internal SP, then
|
||||
// we just ignore any state in the main SP. For example, if the user
|
||||
// imports an older AAPS settings file with an old pump state, and a
|
||||
// Combo is already paired with AAPS, then it makes no sense to overwrite
|
||||
// the current pump state with the old one from the imported settings.
|
||||
if (pumpStateStore.getAvailablePumpStateAddresses().isEmpty()) {
|
||||
aapsLogger.info(LTag.PUMP, "There is no pump state in the internal SP; trying to copy a pump state from the main AAPS SP")
|
||||
pumpStateStore.copyAllValuesFromAAPSMainSP(commit = true)
|
||||
val btAddress = pumpStateStore.getAvailablePumpStateAddresses().firstOrNull()
|
||||
if (btAddress == null)
|
||||
aapsLogger.info(LTag.PUMP, "No pump state found in the main AAPS SP; continuing without a pump state (implying that no pump is paired)")
|
||||
else
|
||||
aapsLogger.info(LTag.PUMP, "Pump state found in the main AAPS SP (bluetooth address: $btAddress); continuing with that state")
|
||||
} else {
|
||||
// Copy over the internal SP pump state to the main AAPS SP. If the user
|
||||
// just imported AAPS settings, and said settings contained an old pump
|
||||
// state, then that old pump state is ignored if there is already a
|
||||
// current pump state in the internal SP - but we still need to make sure
|
||||
// the old pump state in the main AAPS SP is replaced by the current one.
|
||||
aapsLogger.debug(LTag.PUMP, "Copying internal SP pump state to main AAPS SP")
|
||||
pumpStateStore.copyAllValuesToAAPSMainSP(commit = false)
|
||||
}
|
||||
|
||||
aapsLogger.debug(LTag.PUMP, "Creating bluetooth interface")
|
||||
bluetoothInterface = AndroidBluetoothInterface(context)
|
||||
|
||||
|
@ -624,6 +662,11 @@ class ComboV2Plugin @Inject constructor (
|
|||
override fun disconnect(reason: String) {
|
||||
aapsLogger.debug(LTag.PUMP, "Disconnecting from Combo; reason: $reason")
|
||||
disconnectInternal(forceDisconnect = false)
|
||||
|
||||
// Sync up the TBR and nonce states in the main AAPS SP. We don't do this all the
|
||||
// time since this is unnecessary waste of resources. It is sufficient to update
|
||||
// those once AAPS is done with the connection.
|
||||
pumpStateStore.copyVariantValuesToAAPSMainSP(commit = false)
|
||||
}
|
||||
|
||||
// This is called when (a) the AAPS watchdog is about to toggle
|
||||
|
@ -1048,17 +1091,34 @@ class ComboV2Plugin @Inject constructor (
|
|||
return pumpEnactResult
|
||||
}
|
||||
|
||||
private fun setTbrInternal(percentage: Int, durationInMinutes: Int, tbrType: ComboCtlTbr.Type, force100Percent: Boolean, pumpEnactResult: PumpEnactResult) {
|
||||
private fun setTbrInternal(
|
||||
percentage: Int,
|
||||
durationInMinutes: Int,
|
||||
tbrType: ComboCtlTbr.Type,
|
||||
force100Percent: Boolean,
|
||||
pumpEnactResult: PumpEnactResult
|
||||
) {
|
||||
runBlocking {
|
||||
try {
|
||||
executeCommand {
|
||||
pump!!.setTbr(percentage, durationInMinutes, tbrType, force100Percent)
|
||||
}
|
||||
val setTbrOutcome = pump!!.setTbr(percentage, durationInMinutes, tbrType, force100Percent)
|
||||
|
||||
pumpEnactResult.apply {
|
||||
success = true
|
||||
enacted = true
|
||||
comment = rh.gs(R.string.combov2_setting_tbr_succeeded)
|
||||
val tbrComment = when (setTbrOutcome) {
|
||||
ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR ->
|
||||
rh.gs(R.string.combov2_setting_tbr_succeeded)
|
||||
ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR ->
|
||||
rh.gs(R.string.combov2_set_emulated_100_tbr)
|
||||
ComboCtlPump.SetTbrOutcome.LETTING_EMULATED_100_TBR_FINISH ->
|
||||
rh.gs(R.string.combov2_letting_emulated_100_tbr_finish)
|
||||
ComboCtlPump.SetTbrOutcome.IGNORED_REDUNDANT_100_TBR ->
|
||||
rh.gs(R.string.combov2_ignoring_redundant_100_tbr)
|
||||
}
|
||||
|
||||
pumpEnactResult.apply {
|
||||
success = true
|
||||
enacted = true
|
||||
comment = tbrComment
|
||||
}
|
||||
}
|
||||
} catch (e: QuantityNotChangingException) {
|
||||
aapsLogger.error(LTag.PUMP, "TBR percentage adjustment hit a limit: $e")
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
package info.nightscout.pump.combov2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.annotation.StringRes
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
|
||||
// This is a copy of the AAPS SPImplementation. We keep this to be able
|
||||
// to set up a custom internal SP store for the Combo pump state.
|
||||
class InternalSP(
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val context: Context
|
||||
) : SP {
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun edit(commit: Boolean, block: SP.Editor.() -> Unit) {
|
||||
val spEdit = sharedPreferences.edit()
|
||||
|
||||
val edit = object : SP.Editor {
|
||||
override fun clear() {
|
||||
spEdit.clear()
|
||||
}
|
||||
|
||||
override fun remove(@StringRes resourceID: Int) {
|
||||
spEdit.remove(context.getString(resourceID))
|
||||
}
|
||||
override fun remove(key: String) {
|
||||
spEdit.remove(key)
|
||||
}
|
||||
|
||||
override fun putBoolean(key: String, value: Boolean) {
|
||||
spEdit.putBoolean(key, value)
|
||||
}
|
||||
override fun putBoolean(@StringRes resourceID: Int, value: Boolean) {
|
||||
spEdit.putBoolean(context.getString(resourceID), value)
|
||||
}
|
||||
override fun putDouble(key: String, value: Double) {
|
||||
spEdit.putString(key, value.toString())
|
||||
}
|
||||
override fun putDouble(@StringRes resourceID: Int, value: Double) {
|
||||
spEdit.putString(context.getString(resourceID), value.toString())
|
||||
}
|
||||
override fun putLong(key: String, value: Long) {
|
||||
spEdit.putLong(key, value)
|
||||
}
|
||||
override fun putLong(@StringRes resourceID: Int, value: Long) {
|
||||
spEdit.putLong(context.getString(resourceID), value)
|
||||
}
|
||||
override fun putInt(key: String, value: Int) {
|
||||
spEdit.putInt(key, value)
|
||||
}
|
||||
override fun putInt(@StringRes resourceID: Int, value: Int) {
|
||||
spEdit.putInt(context.getString(resourceID), value)
|
||||
}
|
||||
override fun putString(key: String, value: String) {
|
||||
spEdit.putString(key, value)
|
||||
}
|
||||
override fun putString(@StringRes resourceID: Int, value: String) {
|
||||
spEdit.putString(context.getString(resourceID), value)
|
||||
}
|
||||
}
|
||||
|
||||
block(edit)
|
||||
|
||||
if (commit)
|
||||
spEdit.commit()
|
||||
else
|
||||
spEdit.apply()
|
||||
}
|
||||
|
||||
override fun getAll(): Map<String, *> = sharedPreferences.all
|
||||
|
||||
override fun clear() = sharedPreferences.edit().clear().apply()
|
||||
|
||||
override fun contains(key: String): Boolean = sharedPreferences.contains(key)
|
||||
|
||||
override fun contains(resourceId: Int): Boolean = sharedPreferences.contains(context.getString(resourceId))
|
||||
|
||||
override fun remove(resourceID: Int) =
|
||||
sharedPreferences.edit().remove(context.getString(resourceID)).apply()
|
||||
|
||||
override fun remove(key: String) =
|
||||
sharedPreferences.edit().remove(key).apply()
|
||||
|
||||
override fun getString(resourceID: Int, defaultValue: String): String =
|
||||
sharedPreferences.getString(context.getString(resourceID), defaultValue) ?: defaultValue
|
||||
|
||||
override fun getStringOrNull(resourceID: Int, defaultValue: String?): String? =
|
||||
sharedPreferences.getString(context.getString(resourceID), defaultValue) ?: defaultValue
|
||||
|
||||
override fun getStringOrNull(key: String, defaultValue: String?): String? =
|
||||
sharedPreferences.getString(key, defaultValue)
|
||||
|
||||
override fun getString(key: String, defaultValue: String): String =
|
||||
sharedPreferences.getString(key, defaultValue) ?: defaultValue
|
||||
|
||||
override fun getBoolean(resourceID: Int, defaultValue: Boolean): Boolean {
|
||||
return try {
|
||||
sharedPreferences.getBoolean(context.getString(resourceID), defaultValue)
|
||||
} catch (e: Exception) {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBoolean(key: String, defaultValue: Boolean): Boolean {
|
||||
return try {
|
||||
sharedPreferences.getBoolean(key, defaultValue)
|
||||
} catch (e: Exception) {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDouble(resourceID: Int, defaultValue: Double): Double =
|
||||
SafeParse.stringToDouble(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()))
|
||||
|
||||
override fun getDouble(key: String, defaultValue: Double): Double =
|
||||
SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString()))
|
||||
|
||||
override fun getInt(resourceID: Int, defaultValue: Int): Int {
|
||||
return try {
|
||||
sharedPreferences.getInt(context.getString(resourceID), defaultValue)
|
||||
} catch (e: Exception) {
|
||||
SafeParse.stringToInt(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInt(key: String, defaultValue: Int): Int {
|
||||
return try {
|
||||
sharedPreferences.getInt(key, defaultValue)
|
||||
} catch (e: Exception) {
|
||||
SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLong(resourceID: Int, defaultValue: Long): Long {
|
||||
return try {
|
||||
sharedPreferences.getLong(context.getString(resourceID), defaultValue)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
SafeParse.stringToLong(sharedPreferences.getString(context.getString(resourceID), defaultValue.toString()))
|
||||
} catch (e: Exception) {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLong(key: String, defaultValue: Long): Long {
|
||||
return try {
|
||||
sharedPreferences.getLong(key, defaultValue)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString()))
|
||||
} catch (e: Exception) {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun incLong(resourceID: Int) {
|
||||
val value = getLong(resourceID, 0) + 1L
|
||||
sharedPreferences.edit().putLong(context.getString(resourceID), value).apply()
|
||||
}
|
||||
|
||||
override fun putBoolean(key: String, value: Boolean) = sharedPreferences.edit().putBoolean(key, value).apply()
|
||||
|
||||
override fun putBoolean(resourceID: Int, value: Boolean) =
|
||||
sharedPreferences.edit().putBoolean(context.getString(resourceID), value).apply()
|
||||
|
||||
override fun putDouble(key: String, value: Double) =
|
||||
sharedPreferences.edit().putString(key, value.toString()).apply()
|
||||
|
||||
override fun putDouble(resourceID: Int, value: Double) {
|
||||
sharedPreferences.edit().putString(context.getString(resourceID), value.toString()).apply()
|
||||
}
|
||||
|
||||
override fun putLong(key: String, value: Long) =
|
||||
sharedPreferences.edit().putLong(key, value).apply()
|
||||
|
||||
override fun putLong(resourceID: Int, value: Long) =
|
||||
sharedPreferences.edit().putLong(context.getString(resourceID), value).apply()
|
||||
|
||||
override fun putInt(key: String, value: Int) =
|
||||
sharedPreferences.edit().putInt(key, value).apply()
|
||||
|
||||
override fun putInt(resourceID: Int, value: Int) =
|
||||
sharedPreferences.edit().putInt(context.getString(resourceID), value).apply()
|
||||
|
||||
override fun incInt(resourceID: Int) {
|
||||
val value = getInt(resourceID, 0) + 1
|
||||
sharedPreferences.edit().putInt(context.getString(resourceID), value).apply()
|
||||
}
|
||||
|
||||
override fun putString(resourceID: Int, value: String) =
|
||||
sharedPreferences.edit().putString(context.getString(resourceID), value).apply()
|
||||
|
||||
override fun putString(key: String, value: String) =
|
||||
sharedPreferences.edit().putString(key, value).apply()
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
package info.nightscout.pump.combov2
|
||||
|
||||
import info.nightscout.comboctl.base.BluetoothAddress
|
||||
import info.nightscout.comboctl.base.CurrentTbrState
|
||||
import info.nightscout.comboctl.base.InvariantPumpData
|
||||
import info.nightscout.comboctl.base.Nonce
|
||||
import info.nightscout.comboctl.base.PumpStateStore
|
||||
import info.nightscout.comboctl.base.Tbr
|
||||
import info.nightscout.comboctl.base.toBluetoothAddress
|
||||
import info.nightscout.comboctl.base.toCipher
|
||||
import info.nightscout.comboctl.base.toNonce
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateInt
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateLong
|
||||
import info.nightscout.shared.sharedPreferences.SPDelegateString
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.UtcOffset
|
||||
|
||||
/**
|
||||
* AndroidAPS [SP] based pump state store.
|
||||
*
|
||||
* This store is set up to contain a single paired pump. AndroidAPS is not
|
||||
* designed to handle multiple pumps, so this simplification makes sense.
|
||||
* This affects all accessors, which
|
||||
*/
|
||||
class SPPumpStateStore(private val sp: SP) : PumpStateStore {
|
||||
private var btAddress: String
|
||||
by SPDelegateString(sp, BT_ADDRESS_KEY, "")
|
||||
|
||||
// The nonce is updated with commit instead of apply to make sure
|
||||
// is atomically written to storage synchronously, minimizing
|
||||
// the likelihood that it could be lost due to app crashes etc.
|
||||
// It is very important to not lose the nonce, hence that choice.
|
||||
private var nonceString: String
|
||||
by SPDelegateString(sp, NONCE_KEY, Nonce.nullNonce().toString(), commit = true)
|
||||
|
||||
private var cpCipherString: String
|
||||
by SPDelegateString(sp, CP_CIPHER_KEY, "")
|
||||
private var pcCipherString: String
|
||||
by SPDelegateString(sp, PC_CIPHER_KEY, "")
|
||||
private var keyResponseAddressInt: Int
|
||||
by SPDelegateInt(sp, KEY_RESPONSE_ADDRESS_KEY, 0)
|
||||
private var pumpID: String
|
||||
by SPDelegateString(sp, PUMP_ID_KEY, "")
|
||||
private var tbrTimestamp: Long
|
||||
by SPDelegateLong(sp, TBR_TIMESTAMP_KEY, 0)
|
||||
private var tbrPercentage: Int
|
||||
by SPDelegateInt(sp, TBR_PERCENTAGE_KEY, 0)
|
||||
private var tbrDuration: Int
|
||||
by SPDelegateInt(sp, TBR_DURATION_KEY, 0)
|
||||
private var tbrType: String
|
||||
by SPDelegateString(sp, TBR_TYPE_KEY, "")
|
||||
private var utcOffsetSeconds: Int
|
||||
by SPDelegateInt(sp, UTC_OFFSET_KEY, 0)
|
||||
|
||||
override fun createPumpState(
|
||||
pumpAddress: BluetoothAddress,
|
||||
invariantPumpData: InvariantPumpData,
|
||||
utcOffset: UtcOffset,
|
||||
tbrState: CurrentTbrState
|
||||
) {
|
||||
// Write these values via edit() instead of using the delegates
|
||||
// above to be able to write all of them with a single commit.
|
||||
sp.edit(commit = true) {
|
||||
putString(BT_ADDRESS_KEY, pumpAddress.toString().uppercase())
|
||||
putString(CP_CIPHER_KEY, invariantPumpData.clientPumpCipher.toString())
|
||||
putString(PC_CIPHER_KEY, invariantPumpData.pumpClientCipher.toString())
|
||||
putInt(KEY_RESPONSE_ADDRESS_KEY, invariantPumpData.keyResponseAddress.toInt() and 0xFF)
|
||||
putString(PUMP_ID_KEY, invariantPumpData.pumpID)
|
||||
putLong(TBR_TIMESTAMP_KEY, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.timestamp.epochSeconds else -1)
|
||||
putInt(TBR_PERCENTAGE_KEY, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.percentage else -1)
|
||||
putInt(TBR_DURATION_KEY, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.durationInMinutes else -1)
|
||||
putString(TBR_TYPE_KEY, if (tbrState is CurrentTbrState.TbrStarted) tbrState.tbr.type.stringId else "")
|
||||
putInt(UTC_OFFSET_KEY, utcOffset.totalSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deletePumpState(pumpAddress: BluetoothAddress): Boolean {
|
||||
val hasState = sp.contains(NONCE_KEY)
|
||||
|
||||
sp.edit(commit = true) {
|
||||
remove(BT_ADDRESS_KEY)
|
||||
remove(NONCE_KEY)
|
||||
remove(CP_CIPHER_KEY)
|
||||
remove(PC_CIPHER_KEY)
|
||||
remove(KEY_RESPONSE_ADDRESS_KEY)
|
||||
remove(TBR_TIMESTAMP_KEY)
|
||||
remove(TBR_PERCENTAGE_KEY)
|
||||
remove(TBR_DURATION_KEY)
|
||||
remove(TBR_TYPE_KEY)
|
||||
remove(UTC_OFFSET_KEY)
|
||||
}
|
||||
|
||||
return hasState
|
||||
}
|
||||
|
||||
override fun hasPumpState(pumpAddress: BluetoothAddress) =
|
||||
sp.contains(NONCE_KEY)
|
||||
|
||||
override fun getAvailablePumpStateAddresses() =
|
||||
if (btAddress.isBlank()) setOf() else setOf(btAddress.toBluetoothAddress())
|
||||
|
||||
override fun getInvariantPumpData(pumpAddress: BluetoothAddress) = InvariantPumpData(
|
||||
clientPumpCipher = cpCipherString.toCipher(),
|
||||
pumpClientCipher = pcCipherString.toCipher(),
|
||||
keyResponseAddress = keyResponseAddressInt.toByte(),
|
||||
pumpID = pumpID
|
||||
)
|
||||
|
||||
override fun getCurrentTxNonce(pumpAddress: BluetoothAddress) = nonceString.toNonce()
|
||||
|
||||
override fun setCurrentTxNonce(pumpAddress: BluetoothAddress, currentTxNonce: Nonce) {
|
||||
nonceString = currentTxNonce.toString()
|
||||
}
|
||||
|
||||
override fun getCurrentUtcOffset(pumpAddress: BluetoothAddress) =
|
||||
UtcOffset(seconds = utcOffsetSeconds)
|
||||
|
||||
override fun setCurrentUtcOffset(pumpAddress: BluetoothAddress, utcOffset: UtcOffset) {
|
||||
utcOffsetSeconds = utcOffset.totalSeconds
|
||||
}
|
||||
|
||||
override fun getCurrentTbrState(pumpAddress: BluetoothAddress) =
|
||||
if (tbrTimestamp >= 0)
|
||||
CurrentTbrState.TbrStarted(Tbr(
|
||||
timestamp = Instant.fromEpochSeconds(tbrTimestamp),
|
||||
percentage = tbrPercentage,
|
||||
durationInMinutes = tbrDuration,
|
||||
type = Tbr.Type.fromStringId(tbrType)!!
|
||||
))
|
||||
else
|
||||
CurrentTbrState.NoTbrOngoing
|
||||
|
||||
|
||||
override fun setCurrentTbrState(pumpAddress: BluetoothAddress, currentTbrState: CurrentTbrState) {
|
||||
when (currentTbrState) {
|
||||
is CurrentTbrState.TbrStarted -> {
|
||||
tbrTimestamp = currentTbrState.tbr.timestamp.epochSeconds
|
||||
tbrPercentage = currentTbrState.tbr.percentage
|
||||
tbrDuration = currentTbrState.tbr.durationInMinutes
|
||||
tbrType = currentTbrState.tbr.type.stringId
|
||||
}
|
||||
else -> {
|
||||
tbrTimestamp = -1
|
||||
tbrPercentage = -1
|
||||
tbrDuration = -1
|
||||
tbrType = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BT_ADDRESS_KEY = "combov2-bt-address-key"
|
||||
const val NONCE_KEY = "combov2-nonce-key"
|
||||
const val CP_CIPHER_KEY = "combov2-cp-cipher-key"
|
||||
const val PC_CIPHER_KEY = "combov2-pc-cipher-key"
|
||||
const val KEY_RESPONSE_ADDRESS_KEY = "combov2-key-response-address-key"
|
||||
const val PUMP_ID_KEY = "combov2-pump-id-key"
|
||||
const val TBR_TIMESTAMP_KEY = "combov2-tbr-timestamp"
|
||||
const val TBR_PERCENTAGE_KEY = "combov2-tbr-percentage"
|
||||
const val TBR_DURATION_KEY = "combov2-tbr-duration"
|
||||
const val TBR_TYPE_KEY = "combov2-tbr-type"
|
||||
const val UTC_OFFSET_KEY = "combov2-utc-offset"
|
||||
}
|
||||
}
|
|
@ -71,6 +71,7 @@ knappene samtidig for å avbryte parringen)\n
|
|||
<string name="combov2_fetching_tdd_history_cmddesc">Henter TDD historikk</string>
|
||||
<string name="combov2_updating_pump_datetime_cmddesc">Oppdaterer dato/klokkeslett i pumpen</string>
|
||||
<string name="combov2_updating_pump_status_cmddesc">Oppdaterer pumpestatus</string>
|
||||
<string name="combov2_pairing_pin_failure">PIN-koden fungerte ikke. Sjekk om det var en skrivefeil. Hvis dette fortsetter å skje, avbryt og prøv å pare enhet på nytt.</string>
|
||||
<string name="combov2_discovery_duration">Søkevarighet (i sekunder)</string>
|
||||
<string name="combov2_verbose_logging">Aktiver detaljert Combo logging</string>
|
||||
<string name="combov2_getting_basal_profile">Henter basalprofil; %1$d registrering(er) lest</string>
|
||||
|
@ -109,4 +110,12 @@ knappene samtidig for å avbryte parringen)\n
|
|||
<string name="combov2_short_status_battery_state_low">lavt</string>
|
||||
<string name="combov2_short_status_battery_state_full">full</string>
|
||||
<string name="combov2_short_status_battery_state">Batt: %s</string>
|
||||
<string name="combov2_automatic_reservoir_entry">Autodetekter og automatisk registrer bytte av insulireservoar</string>
|
||||
<string name="combov2_automatic_battery_entry">Autodetekter og automatisk registrer batteribytte</string>
|
||||
<string name="combov2_note_reservoir_change">Bytte av insulinreservoar ble automatisk registrert av Combo driveren</string>
|
||||
<string name="combov2_note_battery_change">Bytte av batteri ble automatisk registrert av Combo driveren</string>
|
||||
<string name="combov2_timezone_changed">Tidssone endret</string>
|
||||
<string name="combov2_datetime_changed">Dato og/eller klokkeslett endret</string>
|
||||
<string name="combov2_dst_started">Sommertid (DST) er startet</string>
|
||||
<string name="combov2_dst_ended">Sommertid (DST) er avsluttet</string>
|
||||
</resources>
|
||||
|
|
|
@ -28,14 +28,73 @@
|
|||
<string name="bluetooth_address">Adresa Bluetooth</string>
|
||||
<string name="combov2_start_pairing">Spustiť párovanie</string>
|
||||
<string name="combov2_pairing_in_progress">Prebieha Combo párovanie</string>
|
||||
<string name="combov2_pairing_start_steps">Kroky k vykonaniu párovania s Combo:\n\n
|
||||
1. Na vašej pumpe prejdite do nastavení Bluetooth\n
|
||||
2. Zkontrolujte, či je zariadenie už zobrazené ako spárované. pokiaľ áno, prejdite na obrazovku pumpy \"Odstrániť zariadenie\" a odstrániť/zrušiť párovanie tohoto zariadenia\n
|
||||
3. Prejdite na obrazovku pumpy \"Pridať zariadenie\" a spárujte na pumpe\n
|
||||
4. Kliknite na tlačítko \"Spustiť párovanie\" nižšie pre zahájenie párovania v AndroidAPS\n</string>
|
||||
<string name="combov2_steps_if_no_connection_during_pairing">Po nejakej dobe sa na obrazovke pumpy zobrazí meno telefónu; stlačte KONTROLA pre potvrdenie.\n\n
|
||||
Po úspešnom dokončení párovania, potvrďte dokončenie párovania na vašej pumpe a vráťte sa na hlavnú obrazovku pumpy dvojitým stlačením tlačítka KONIEC.\n\n
|
||||
Pokiaľ po viac ako ~5 minútach nie je nadviazané žiadne spojenie:\n\n
|
||||
1. Stlačte tlačítko Späť alebo tlačítko \"Zrušiť párovanie\"\n
|
||||
2. Zrušte párovanie na Combo (súčasne stlačte tlačítka „UP i MENU“ pre zrušenie párovania)\n
|
||||
3. Skúste znova spárovať</string>
|
||||
<string name="combov2_enter_pin">Zadajte PIN</string>
|
||||
<string name="combov2_cancel_pairing">Zrušiť párovanie</string>
|
||||
<string name="combov2_pin_hint">10-miestny PIN</string>
|
||||
<string name="combov2_pairing_finished_successfully">Úspešne spárované s Combo</string>
|
||||
<string name="combov2_pairing_cancelled">Párovanie s Combo zrušené užívateľom</string>
|
||||
<string name="combov2_pairing_combo_scan_timeout_reached">Časový limit pre vyhľadávanie Combo dosiahnutý</string>
|
||||
<string name="combov2_pairing_failed_due_to_error">Párovanie se nepodarilo z dôvodu chyby: %1$s</string>
|
||||
<string name="combov2_pairing_aborted_unknown_reasons">Párovanie prerušené z neznámych dôvodov</string>
|
||||
<string name="combov2_scanning_for_pump">Vyhľadávanie pumpy</string>
|
||||
<string name="combov2_establishing_bt_connection">Nadväzovanie Bluetooth pripojenia (pokus č. %1$d)</string>
|
||||
<string name="combov2_pairing_performing_handshake">Nadväzovanie pripojenia s pumpou</string>
|
||||
<string name="combov2_pairing_pump_requests_pin">Pumpa vyžaduje desaťmiestny kód PIN</string>
|
||||
<string name="combov2_pairing_finishing">Dokončovanie párovania</string>
|
||||
<string name="combov2_no_connection_for_n_mins">Žiadne spojenie v priebehu %1$d min</string>
|
||||
<string name="combov2_less_than_one_minute_ago">Pred menej ako minútou</string>
|
||||
<string name="combov2_setting_current_pump_time">Nastavenie aktuálneho času pumpy</string>
|
||||
<string name="combov2_setting_current_pump_date">Nastavenie aktuálneho dátumu pumpy</string>
|
||||
<string name="combov2_not_initialized">Nie je inicializovaný</string>
|
||||
<string name="combov2_checking_pump">Kontrola pumpy</string>
|
||||
<string name="combov2_ready">Pripravený</string>
|
||||
<string name="combov2_suspended">Pozastavené</string>
|
||||
<string name="combov2_pump_is_suspended">Pumpa je pozastavená</string>
|
||||
<string name="combov2_executing_command">Vykonávanie príkazu</string>
|
||||
<string name="combov2_getting_basal_profile_cmddesc">Načítavam bazálny profil</string>
|
||||
<string name="combov2_setting_basal_profile_cmddesc">Nastavenie bazálneho profilu</string>
|
||||
<string name="combov2_setting_tbr_cmddesc">Nastavenie %1$d%% dočasného bazálu na %2$d minút</string>
|
||||
<string name="combov2_cancelling_tbr">Zrušenie prebiehajúceho dočasného bazálu</string>
|
||||
<string name="combov2_delivering_bolus_cmddesc">Podávanie %1$.1f JI</string>
|
||||
<string name="combov2_fetching_tdd_history_cmddesc">Načítavam CDD históriu</string>
|
||||
<string name="combov2_updating_pump_datetime_cmddesc">Aktualizácia dátumu a času v pumpe</string>
|
||||
<string name="combov2_updating_pump_status_cmddesc">Načítavam stav pumpy</string>
|
||||
<string name="combov2_pairing_pin_failure">PIN nefungoval. Skontrolujte, či ste neurobili preklep. Pokiaľ sa to stále deje, zrušte a opakujte párovanie.</string>
|
||||
<string name="combov2_discovery_duration">Dĺžka hľadania (v sekundách)</string>
|
||||
<string name="combov2_verbose_logging">Povoliť podrobné logovanie Combo</string>
|
||||
<string name="combov2_getting_basal_profile">Získávanie bazálneho profilu; čítanie %1$d. faktora</string>
|
||||
<string name="combov2_setting_basal_profile">Nastavenie bazálneho profilu; zapisovanie %1$d. faktora</string>
|
||||
<string name="combov2_delivering_bolus">Podávanie bolusu (podané %1$.1f z %2$.1f JI)</string>
|
||||
<string name="combov2_cannot_deliver_pump_suspended">Nie je možné podať bolus - pumpa je pozastavená</string>
|
||||
<string name="combov2_insufficient_insulin_in_reservoir">Nedostatok inzulínu v zásobníku</string>
|
||||
<string name="combov2_bolus_cancelled">Bolus zrušený</string>
|
||||
<string name="combov2_bolus_delivery_failed">Podávanie inzulínu zlyhalo. Zdá sa, že nebol podaný žiadny bolus. Aby ste si boli istí, skontrolujte pumpu a prípadne pošlite bolus znovu. Aby sa zabránilo nechcenému dvojitému bolusu, podanie bolusu nie je automaticky opakované.</string>
|
||||
<string name="combov2_bolus_not_delivered">Bolus nebol podaný</string>
|
||||
<string name="combov2_cannot_access_pump_data">Nie je možné získať prístup k dátam pumpy; pumpa musí byť znova spárovaná</string>
|
||||
<string name="combov2_unaccounted_bolus_detected_cancelling_bolus">Zistené nečakané bolusy. Z bezpečnostných dôvodov bolus zrušený.</string>
|
||||
<string name="combov2_incorrect_active_basal_profile">Nesprávny aktívny bazálny profil; profil 1 musí byť aktívny, nie profil %1$d</string>
|
||||
<string name="combov2_unrecognized_alert">Nerozpoznané Combo upozornenie</string>
|
||||
<string name="combov2_combo_alert">Combo upozornenie</string>
|
||||
<string name="combov2_current_tbr">%1$d%% (%2$d min zostáva)</string>
|
||||
<string name="combov2_current_tbr_less_than_1min">%1$d%% (zostáva menej ako 1 min)</string>
|
||||
<string name="combov2_load_tdds_cancelled">Načítanie CDD zrušené</string>
|
||||
<string name="combov2_retrieving_tdds_failed">Načítanie CDD zlyhalo</string>
|
||||
<string name="combov2_battery_low_warning">Batéria v pumpe je takmer vybitá</string>
|
||||
<string name="combov2_reservoir_low_warning">V zásobníku je málo inzulínu</string>
|
||||
<string name="combov2_setting_tbr_succeeded">Nastavenie dočasného bazálu bolo úspešné</string>
|
||||
<string name="combov2_setting_tbr_failed">Nastavenie dočasného bazálu zlyhalo</string>
|
||||
<string name="combov2_hit_unexpected_tbr_limit">Pri úprave dočasného bazálu došlo k neočekávanému limitu: vyžadované %1$d%%, dosiahnutý limit %1$d%%</string>
|
||||
<string name="combov2_short_status_last_connection">Posledné spoj: pred %1$d min</string>
|
||||
<string name="combov2_short_status_temp_basal">Doč. bazál: %s</string>
|
||||
<string name="combov2_short_status_reservoir">Zásobník: %dJI</string>
|
||||
|
|
|
@ -107,6 +107,9 @@ buttons at the same time to cancel pairing)\n
|
|||
<string name="combov2_reservoir_low_warning">Pump reservoir level is low</string>
|
||||
<string name="combov2_setting_tbr_succeeded">Setting TBR succeeded</string>
|
||||
<string name="combov2_setting_tbr_failed">Setting TBR failed</string>
|
||||
<string name="combov2_set_emulated_100_tbr">Set emulated 100% TBR</string>
|
||||
<string name="combov2_letting_emulated_100_tbr_finish">Letting ongoing emulated 100% TBR finish</string>
|
||||
<string name="combov2_ignoring_redundant_100_tbr">Ignoring redundant 100% TBR request</string>
|
||||
<string name="combov2_hit_unexpected_tbr_limit">Unexpected limit encountered while adjusting TBR: target percentage was %1$d%%, hit a limit at %1$d%%</string>
|
||||
<string name="combov2_cannot_set_absolute_tbr_if_basal_zero">Cannot set absolute TBR if base basal rate is zero</string>
|
||||
<string name="combov2_pair_with_pump_summary">Pair AndroidAPS and Android with a currently unpaired Accu-Chek Combo pump</string>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
android:key="@string/key_combov2_unpair_pump"
|
||||
android:shouldDisableView="true"/>
|
||||
|
||||
<SeekBarPreference
|
||||
<info.nightscout.core.ui.elements.IntSeekBarPreference
|
||||
android:key="@string/key_combov2_discovery_duration"
|
||||
android:title="@string/combov2_discovery_duration"
|
||||
android:min="30"
|
||||
|
|
|
@ -157,7 +157,7 @@ class DanaRKoreanPlugin @Inject constructor(
|
|||
result
|
||||
} else {
|
||||
val result = PumpEnactResult(injector)
|
||||
result.success(false).bolusDelivered(0.0).carbsDelivered(0.0).comment(info.nightscout.core.ui.R.string.invalid_input)
|
||||
result.success(false).bolusDelivered(0.0).comment(info.nightscout.core.ui.R.string.invalid_input)
|
||||
aapsLogger.error("deliverTreatment: Invalid input")
|
||||
result
|
||||
}
|
||||
|
|
|
@ -197,8 +197,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
|
|||
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) carbs, carbTimeStamp, t);
|
||||
PumpEnactResult result = new PumpEnactResult(getInjector());
|
||||
result.success(connectionOK && Math.abs(detailedBolusInfo.insulin - t.getInsulin()) < pumpDescription.getBolusStep())
|
||||
.bolusDelivered(t.getInsulin())
|
||||
.carbsDelivered(detailedBolusInfo.carbs);
|
||||
.bolusDelivered(t.getInsulin());
|
||||
if (!result.getSuccess())
|
||||
result.comment(rh.gs(info.nightscout.pump.dana.R.string.boluserrorcode, detailedBolusInfo.insulin, t.getInsulin(),
|
||||
danaPump.getBolusStartErrorCode()));
|
||||
|
@ -209,7 +208,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
|
|||
return result;
|
||||
} else {
|
||||
PumpEnactResult result = new PumpEnactResult(getInjector());
|
||||
result.success(false).bolusDelivered(0d).carbsDelivered(0d).comment(info.nightscout.core.ui.R.string.invalid_input);
|
||||
result.success(false).bolusDelivered(0d).comment(info.nightscout.core.ui.R.string.invalid_input);
|
||||
aapsLogger.error("deliverTreatment: Invalid input");
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
|
|||
}
|
||||
})
|
||||
);
|
||||
danaPump.setSerialNumber(sp.getString(info.nightscout.pump.dana.R.string.key_danar_bt_name, "")); // fill at start to allow password reset
|
||||
}
|
||||
|
||||
@Override protected void onStop() {
|
||||
|
|
|
@ -172,8 +172,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
|
|||
connectionOK = sExecutionService.bolus(detailedBolusInfo.insulin, (int) detailedBolusInfo.carbs, detailedBolusInfo.getCarbsTimestamp() != null ? detailedBolusInfo.getCarbsTimestamp() : detailedBolusInfo.timestamp, t);
|
||||
PumpEnactResult result = new PumpEnactResult(getInjector());
|
||||
result.success(connectionOK && Math.abs(detailedBolusInfo.insulin - t.getInsulin()) < pumpDescription.getBolusStep())
|
||||
.bolusDelivered(t.getInsulin())
|
||||
.carbsDelivered(detailedBolusInfo.carbs);
|
||||
.bolusDelivered(t.getInsulin());
|
||||
if (!result.getSuccess())
|
||||
result.comment(rh.gs(info.nightscout.pump.dana.R.string.boluserrorcode, detailedBolusInfo.insulin, t.getInsulin(), danaPump.getBolusStartErrorCode()));
|
||||
else
|
||||
|
@ -199,7 +198,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
|
|||
return result;
|
||||
} else {
|
||||
PumpEnactResult result = new PumpEnactResult(getInjector());
|
||||
result.success(false).bolusDelivered(0d).carbsDelivered(0d).comment(info.nightscout.core.ui.R.string.invalid_input);
|
||||
result.success(false).bolusDelivered(0d).comment(info.nightscout.core.ui.R.string.invalid_input);
|
||||
aapsLogger.error("deliverTreatment: Invalid input");
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ class DanaRPluginTest : TestBaseWithProfile() {
|
|||
@BeforeEach
|
||||
fun prepareMocks() {
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, "")).thenReturn("")
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danar_bt_name, "")).thenReturn("")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.pumplimit)).thenReturn("pump limit")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)).thenReturn("it must be positive value")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s")
|
||||
|
|
|
@ -42,6 +42,7 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() {
|
|||
@BeforeEach
|
||||
fun prepareMocks() {
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, "")).thenReturn("")
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danar_bt_name, "")).thenReturn("")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.pumplimit)).thenReturn("pump limit")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)).thenReturn("it must be positive value")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s")
|
||||
|
|
|
@ -44,15 +44,17 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
|
|||
|
||||
@BeforeEach
|
||||
fun prepareMocks() {
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, ""))
|
||||
.thenReturn("")
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danar_bt_name, "")).thenReturn("")
|
||||
`when`(sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, "")).thenReturn("")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.pumplimit)).thenReturn("pump limit")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)).thenReturn("it must be positive value")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio)).thenReturn("Limiting max basal rate to %1\$.2f U/h because of %2\$s")
|
||||
`when`(rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate)).thenReturn("Limiting max percent rate to %1\$d%% because of %2\$s")
|
||||
danaPump = DanaPump(aapsLogger, sp, dateUtil, profileInstantiator)
|
||||
danaRv2Plugin = DanaRv2Plugin(injector, aapsLogger, aapsSchedulers, rxBus, context, rh, constraintChecker, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage,
|
||||
temporaryBasalStorage, dateUtil, fabricPrivacy, pumpSync, uiInteraction, danaHistoryDatabase)
|
||||
danaRv2Plugin = DanaRv2Plugin(
|
||||
injector, aapsLogger, aapsSchedulers, rxBus, context, rh, constraintChecker, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage,
|
||||
temporaryBasalStorage, dateUtil, fabricPrivacy, pumpSync, uiInteraction, danaHistoryDatabase
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -154,6 +154,7 @@ class DanaRSPlugin @Inject constructor(
|
|||
fun changePump() {
|
||||
mDeviceAddress = sp.getString(info.nightscout.pump.dana.R.string.key_danars_address, "")
|
||||
mDeviceName = sp.getString(info.nightscout.pump.dana.R.string.key_danars_name, "")
|
||||
danaPump.serialNumber = sp.getString(info.nightscout.pump.dana.R.string.key_danars_name, "")
|
||||
danaPump.reset()
|
||||
commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.device_changed), null)
|
||||
}
|
||||
|
@ -306,7 +307,6 @@ class DanaRSPlugin @Inject constructor(
|
|||
val result = PumpEnactResult(injector)
|
||||
result.success = connectionOK && abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep
|
||||
result.bolusDelivered = t.insulin
|
||||
result.carbsDelivered = detailedBolusInfo.carbs
|
||||
if (!result.success) {
|
||||
var error = "" + danaPump.bolusStartErrorCode
|
||||
when (danaPump.bolusStartErrorCode) {
|
||||
|
@ -323,7 +323,6 @@ class DanaRSPlugin @Inject constructor(
|
|||
val result = PumpEnactResult(injector)
|
||||
result.success = false
|
||||
result.bolusDelivered = 0.0
|
||||
result.carbsDelivered = 0.0
|
||||
result.comment = rh.gs(info.nightscout.core.ui.R.string.invalid_input)
|
||||
aapsLogger.error("deliverTreatment: Invalid input")
|
||||
result
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue