refactor ConstraintObject

This commit is contained in:
Milos Kozak 2023-09-19 13:50:25 +02:00
parent 49c44a52b9
commit d939f7ba99
127 changed files with 1818 additions and 1367 deletions

View file

@ -2,6 +2,8 @@ package info.nightscout.sharedtests
import android.annotation.SuppressLint
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.impl.rx.bus.RxBusImpl
import info.nightscout.sharedtests.rx.TestAapsSchedulers
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.extension.ExtendWith
@ -19,11 +21,13 @@ open class TestBase {
val aapsLogger = AAPSLoggerTest()
val aapsSchedulers: AapsSchedulers = TestAapsSchedulers()
lateinit var rxBus: RxBus
@BeforeEach
fun setupLocale() {
Locale.setDefault(Locale.ENGLISH)
System.setProperty("disableFirebase", "true")
rxBus = RxBusImpl(aapsSchedulers, aapsLogger)
}
@SuppressLint("CheckResult")

View file

@ -19,10 +19,10 @@ import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profile.ProfileStore
import info.nightscout.interfaces.utils.DecimalFormatter
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.shared.impl.rx.bus.RxBusImpl
import info.nightscout.shared.interfaces.ProfileUtil
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import org.json.JSONObject
import org.junit.jupiter.api.BeforeEach
@ -45,11 +45,10 @@ open class TestBaseWithProfile : TestBase() {
@Mock lateinit var context: Context
@Mock lateinit var sp: SP
lateinit var dateUtil: DateUtilImpl
lateinit var dateUtil: DateUtil
lateinit var profileUtil: ProfileUtil
lateinit var decimalFormatter: DecimalFormatter
lateinit var hardLimits: HardLimits
val rxBus = RxBusImpl(aapsSchedulers, aapsLogger)
val profileInjector = HasAndroidInjector {
AndroidInjector {

View file

@ -1,102 +1,98 @@
package info.nightscout.androidaps
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
//@LargeTest
//@RunWith(AndroidJUnit4::class)
class RealPumpTest {
/*
companion object {
const val R_PASSWORD = 1234
const val R_SERIAL = "PBB00013LR_P"
}
private val validProfile = "{\"dia\":\"6\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"10\"},{\"time\":\"2:00\",\"value\":\"11\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
@Inject lateinit var pump : info.nightscout.androidaps.danaRv2.DanaRv2Plugin
@Inject lateinit var randomBgPlugin :RandomBgPlugin
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var insulinOrefUltraRapidActingPlugin: InsulinOrefUltraRapidActingPlugin
@Inject lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var actionsPlugin: ActionsPlugin
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var sp: SP
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(MainActivity::class.java)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Before
fun clear() {
sp.clear()
sp.putBoolean(R.string.key_setupwizard_processed, true)
sp.putString(R.string.key_aps_mode, "closed")
MainApp.getDbHelper().resetDatabases()
MainApp.devBranch = false
}
private fun preparePlugins() {
// Source
configBuilderPlugin.performPluginSwitch(randomBgPlugin,true, PluginType.BGSOURCE)
// Profile
configBuilderPlugin.performPluginSwitch(localProfilePlugin, true, PluginType.PROFILE)
val profile = Profile(JSONObject(validProfile), Constants.MGDL)
Assert.assertTrue(profile.isValid("Test"))
localProfilePlugin.profiles.clear()
localProfilePlugin.numOfProfiles = 0
val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(localProfilePlugin.rawProfile, profile, "TestProfile")
localProfilePlugin.addProfile(singleProfile)
val profileSwitch = profileFunction.prepareProfileSwitch(localProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, dateUtil._now())
treatmentsPlugin.addToHistoryProfileSwitch(profileSwitch)
// Insulin
configBuilderPlugin.performPluginSwitch(insulinOrefUltraRapidActingPlugin, true, PluginType.INSULIN)
// Pump
sp.putInt(R.string.key_danar_password, R_PASSWORD)
sp.putString(R.string.key_danar_bt_name, R_SERIAL)
configBuilderPlugin.performPluginSwitch((pump as PluginBase), true, PluginType.PUMP)
// Sensitivity
configBuilderPlugin.performPluginSwitch(sensitivityOref1Plugin, true, PluginType.SENSITIVITY)
// APS
configBuilderPlugin.performPluginSwitch(openAPSSMBPlugin, true, PluginType.APS)
configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP)
// Enable common
configBuilderPlugin.performPluginSwitch(actionsPlugin, true, )
// Disable unneeded
MainApp.getPluginsList().remove(objectivesPlugin)
}
@Test
fun doTest() {
Assert.assertTrue(isRunningTest())
preparePlugins()
while (!pump.isInitialized) {
//log.debug("Waiting for initialization")
SystemClock.sleep(1000)
/*
companion object {
const val R_PASSWORD = 1234
const val R_SERIAL = "PBB00013LR_P"
}
while (true) {
//log.debug("Tick")
SystemClock.sleep(1000)
private val validProfile = "{\"dia\":\"6\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"10\"},{\"time\":\"2:00\",\"value\":\"11\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
@Inject lateinit var pump : info.nightscout.androidaps.danaRv2.DanaRv2Plugin
@Inject lateinit var randomBgPlugin :RandomBgPlugin
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var insulinOrefUltraRapidActingPlugin: InsulinOrefUltraRapidActingPlugin
@Inject lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var actionsPlugin: ActionsPlugin
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var sp: SP
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(MainActivity::class.java)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Before
fun clear() {
sp.clear()
sp.putBoolean(R.string.key_setupwizard_processed, true)
sp.putString(R.string.key_aps_mode, "closed")
MainApp.getDbHelper().resetDatabases()
MainApp.devBranch = false
}
}
*/
private fun preparePlugins() {
// Source
configBuilderPlugin.performPluginSwitch(randomBgPlugin,true, PluginType.BGSOURCE)
// Profile
configBuilderPlugin.performPluginSwitch(localProfilePlugin, true, PluginType.PROFILE)
val profile = Profile(JSONObject(validProfile), Constants.MGDL)
Assert.assertTrue(profile.isValid("Test"))
localProfilePlugin.profiles.clear()
localProfilePlugin.numOfProfiles = 0
val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(localProfilePlugin.rawProfile, profile, "TestProfile")
localProfilePlugin.addProfile(singleProfile)
val profileSwitch = profileFunction.prepareProfileSwitch(localProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, dateUtil._now())
treatmentsPlugin.addToHistoryProfileSwitch(profileSwitch)
// Insulin
configBuilderPlugin.performPluginSwitch(insulinOrefUltraRapidActingPlugin, true, PluginType.INSULIN)
// Pump
sp.putInt(R.string.key_danar_password, R_PASSWORD)
sp.putString(R.string.key_danar_bt_name, R_SERIAL)
configBuilderPlugin.performPluginSwitch((pump as PluginBase), true, PluginType.PUMP)
// Sensitivity
configBuilderPlugin.performPluginSwitch(sensitivityOref1Plugin, true, PluginType.SENSITIVITY)
// APS
configBuilderPlugin.performPluginSwitch(openAPSSMBPlugin, true, PluginType.APS)
configBuilderPlugin.performPluginSwitch(loopPlugin, true, PluginType.LOOP)
// Enable common
configBuilderPlugin.performPluginSwitch(actionsPlugin, true, )
// Disable unneeded
MainApp.getPluginsList().remove(objectivesPlugin)
}
@Test
fun doTest() {
Assert.assertTrue(isRunningTest())
preparePlugins()
while (!pump.isInitialized) {
//log.debug("Waiting for initialization")
SystemClock.sleep(1000)
}
while (true) {
//log.debug("Tick")
SystemClock.sleep(1000)
}
}
*/
}

View file

@ -1,195 +1,191 @@
package info.nightscout.androidaps
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
//@LargeTest
//@RunWith(AndroidJUnit4::class)
class SetupWizardActivityTest {
/*
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java)
/*
@Rule
@JvmField
var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Rule
@JvmField
var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
@Before
fun clear() {
sp.clear()
}
/*
To run from command line
gradlew connectedFullDebugAndroidTest
do not run when your production phone is connected !!!
do this before for running in emulator
adb shell settings put global window_animation_scale 0 &
adb shell settings put global transition_animation_scale 0 &
adb shell settings put global animator_duration_scale 0 &
*/
@Test
fun setupWizardActivityTest() {
sp.clear()
Assert.assertTrue(isRunningTest())
// Welcome page
onView(withId(R.id.next_button)).perform(click())
// Language selection
onView(withText("English")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Agreement page
onView(withText("I UNDERSTAND AND AGREE")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Location permission
var askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
@Before
fun clear() {
sp.clear()
}
// Store permission
askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withText("OK")).perform(click())
/*
To run from command line
gradlew connectedFullDebugAndroidTest
do not run when your production phone is connected !!!
do this before for running in emulator
adb shell settings put global window_animation_scale 0 &
adb shell settings put global transition_animation_scale 0 &
adb shell settings put global animator_duration_scale 0 &
*/
@Test
fun setupWizardActivityTest() {
sp.clear()
Assert.assertTrue(isRunningTest())
// Welcome page
onView(withId(R.id.next_button)).perform(click())
// Language selection
onView(withText("English")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Import settings : skip of found
askButton = onView(withText("IMPORT SETTINGS"))
if (askButton.isDisplayed()) {
// Agreement page
onView(withText("I UNDERSTAND AND AGREE")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Units selection
onView(withText("mmol/L")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).perform(click())
// Display target selection
onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5"))
onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11"))
onView(withId(R.id.next_button)).perform(click())
// NSClient
onView(withId(R.id.next_button)).perform(click())
// Age selection
onView(withText("Adult")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Insulin selection
onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// BG source selection
onView(withText("Random BG")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Profile selection
onView(withText("Local Profile")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Local profile - DIA
onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0"))
// Local profile - IC
onView(withId(R.id.ic_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard())
// Local profile - ISF
onView(withId(R.id.isf_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard())
// Local profile - BAS
onView(withId(R.id.basal_tab)).perform(scrollTo(), click())
onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2))
.perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed()))
.perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0)))
.perform(scrollTo(), click())
onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13)
.perform(click())
// Local profile - TARGET
onView(withId(R.id.target_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("6"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-2-0")), isDisplayed()))
.perform(ViewActions.replaceText("6.5"), ViewActions.closeSoftKeyboard())
onView(withText("Save")).perform(scrollTo(), click())
onView(Matchers.allOf(withId(R.id.localprofile_profileswitch), isDisplayed()))
.perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
// confirm dialog
//onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
clickOkInDialog()
onView(withId(R.id.next_button)).waitAndPerform(click())
// Profile switch
askButton = onView(withText("Do Profile Switch"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
// Location permission
var askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Store permission
askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withText("OK")).perform(click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Import settings : skip of found
askButton = onView(withText("IMPORT SETTINGS"))
if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Units selection
onView(withText("mmol/L")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).perform(click())
// Display target selection
onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5"))
onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11"))
onView(withId(R.id.next_button)).perform(click())
// NSClient
onView(withId(R.id.next_button)).perform(click())
// Age selection
onView(withText("Adult")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Insulin selection
onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// BG source selection
onView(withText("Random BG")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Profile selection
onView(withText("Local Profile")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Local profile - DIA
onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0"))
// Local profile - IC
onView(withId(R.id.ic_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard())
// Local profile - ISF
onView(withId(R.id.isf_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard())
// Local profile - BAS
onView(withId(R.id.basal_tab)).perform(scrollTo(), click())
onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2))
.perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed()))
.perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0)))
.perform(scrollTo(), click())
onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13)
.perform(click())
// Local profile - TARGET
onView(withId(R.id.target_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-1-0")), isDisplayed()))
.perform(ViewActions.replaceText("6"), ViewActions.closeSoftKeyboard())
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-2-0")), isDisplayed()))
.perform(ViewActions.replaceText("6.5"), ViewActions.closeSoftKeyboard())
onView(withText("Save")).perform(scrollTo(), click())
onView(Matchers.allOf(withId(R.id.localprofile_profileswitch), isDisplayed()))
.perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
// onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
// confirm dialog
//onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
clickOkInDialog()
while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Pump
onView(withText("Virtual Pump")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// APS
onView(withText("OpenAPS SMB")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Open Closed Loop
onView(withText("Closed Loop")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Loop
askButton = onView(withText("Enable loop"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Sensitivity
onView(withText("Sensitivity Oref1")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Objectives
onView(allOf(withText("Start"), isDisplayed())).perform(scrollTo(), click())
onView(withId(R.id.finish_button)).waitAndPerform(click())
// Verify settings
Assert.assertEquals(Constants.MMOL, ProfileFunctions.getSystemUnits())
Assert.assertEquals(17.0, HardLimits.maxBolus(), 0.0001) // Adult
Assert.assertTrue(RandomBgPlugin.isEnabled(PluginType.BGSOURCE))
Assert.assertTrue(LocalProfilePlugin.isEnabled(PluginType.PROFILE))
val p = ProfileFunctions.getInstance().profile
Assert.assertNotNull(p)
Assert.assertEquals(2.0, p!!.ic, 0.0001)
Assert.assertEquals(3.0 * Constants.MMOLL_TO_MGDL, p.isfMgdl, 0.0001)
Assert.assertEquals(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP))
Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled())
Assert.assertTrue(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)
}
private fun childAtPosition(
parentMatcher: Matcher<View>, position: Int): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("Child at position $position in parent ")
parentMatcher.describeTo(description)
// Profile switch
askButton = onView(withText("Do Profile Switch"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
// onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
clickOkInDialog()
while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Pump
onView(withText("Virtual Pump")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// APS
onView(withText("OpenAPS SMB")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Open Closed Loop
onView(withText("Closed Loop")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Loop
askButton = onView(withText("Enable loop"))
if (askButton.isDisplayed()) {
askButton.perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
}
// Sensitivity
onView(withText("Sensitivity Oref1")).perform(scrollTo(), click())
onView(withId(R.id.next_button)).waitAndPerform(click())
// Objectives
onView(allOf(withText("Start"), isDisplayed())).perform(scrollTo(), click())
onView(withId(R.id.finish_button)).waitAndPerform(click())
public override fun matchesSafely(view: View): Boolean {
val parent = view.parent
return parent is ViewGroup && parentMatcher.matches(parent)
&& view == parent.getChildAt(position)
// Verify settings
Assert.assertEquals(Constants.MMOL, ProfileFunctions.getSystemUnits())
Assert.assertEquals(17.0, HardLimits.maxBolus(), 0.0001) // Adult
Assert.assertTrue(RandomBgPlugin.isEnabled(PluginType.BGSOURCE))
Assert.assertTrue(LocalProfilePlugin.isEnabled(PluginType.PROFILE))
val p = ProfileFunctions.getInstance().profile
Assert.assertNotNull(p)
Assert.assertEquals(2.0, p!!.ic, 0.0001)
Assert.assertEquals(3.0 * Constants.MMOLL_TO_MGDL, p.isfMgdl, 0.0001)
Assert.assertEquals(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP))
Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled())
Assert.assertTrue(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)
}
private fun childAtPosition(
parentMatcher: Matcher<View>, position: Int): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("Child at position $position in parent ")
parentMatcher.describeTo(description)
}
public override fun matchesSafely(view: View): Boolean {
val parent = view.parent
return parent is ViewGroup && parentMatcher.matches(parent)
&& view == parent.getChildAt(position)
}
}
}
}
*/
*/
}

View file

@ -52,7 +52,7 @@ import info.nightscout.database.entities.UserEntry.Sources
import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.plugin.ActivePlugin
@ -96,7 +96,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var iconsProvider: IconsProvider
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var profileFunction: ProfileFunction

View file

@ -38,6 +38,7 @@ import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils
import info.nightscout.plugins.aps.utils.StaticInjector
import info.nightscout.plugins.general.overview.notifications.NotificationStore
import info.nightscout.plugins.general.themes.ThemeSwitcherPlugin
import info.nightscout.rx.logging.AAPSLogger
@ -77,7 +78,7 @@ class MainApp : DaggerApplication() {
@Inject lateinit var compatDBHelper: CompatDBHelper
@Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil
@Suppress("unused") @Inject lateinit var staticInjector: info.nightscout.plugins.aps.utils.StaticInjector// TODO avoid , here fake only to initialize
@Suppress("unused") @Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var notificationStore: NotificationStore

View file

@ -1,2 +0,0 @@
package info.nightscout.androidaps.di

View file

@ -8,8 +8,7 @@ import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.Config
import info.nightscout.sdk.interfaces.RunningConfiguration
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.ActivePlugin
@ -20,7 +19,7 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.virtual.VirtualPumpPlugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.sdk.interfaces.RunningConfiguration
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
@ -34,8 +33,7 @@ import org.mockito.Mockito.`when`
class LoopPluginTest : TestBase() {
@Mock lateinit var sp: SP
private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger)
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var context: Context

View file

@ -8,7 +8,6 @@ import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.sharedtests.TestBase
@ -37,6 +36,6 @@ class ConfigBuilderPluginTest : TestBase() {
@BeforeEach
fun prepareMock() {
configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, rh, sp, RxBus(aapsSchedulers, aapsLogger), activePlugin, uel, pumpSync, protectionCheck, uiInteraction)
configBuilderPlugin = ConfigBuilderPlugin(injector, aapsLogger, rh, sp, rxBus, activePlugin, uel, pumpSync, protectionCheck, uiInteraction)
}
}

View file

@ -9,13 +9,14 @@ 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.constraints.ConstraintObject
import info.nightscout.database.impl.AppRepository
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType
@ -74,7 +75,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
private lateinit var danaPump: DanaPump
private lateinit var insightDbHelper: InsightDbHelper
private lateinit var constraintChecker: ConstraintsImpl
private lateinit var constraintChecker: ConstraintsCheckerImpl
private lateinit var safetyPlugin: SafetyPlugin
private lateinit var objectivesPlugin: ObjectivesPlugin
private lateinit var comboPlugin: ComboPlugin
@ -94,6 +95,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
if (it is PumpEnactResult) {
it.context = context
}
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@ -134,7 +138,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
`when`(sp.getString(R.string.key_danar_bt_name, "")).thenReturn("")
//SafetyPlugin
constraintChecker = ConstraintsImpl(activePlugin)
constraintChecker = ConstraintsCheckerImpl(activePlugin, injector)
val glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculator, dateUtil, decimalFormatter)
@ -226,7 +230,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
constraintsPluginsList.add(insightPlugin)
constraintsPluginsList.add(openAPSAMAPlugin)
constraintsPluginsList.add(openAPSSMBPlugin)
`when`(activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)).thenReturn(constraintsPluginsList)
`when`(activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)).thenReturn(constraintsPluginsList)
objectivesPlugin.onStart()
}
@ -268,7 +272,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val c = constraintChecker.isAutosensModeEnabled()
assertThat(c.reasonList).hasSize(2) // Safety & Objectives
assertThat(c.mostLimitedReasonList).hasSize(2) // Safety & Objectives
assertThat( c.value()).isFalse()
assertThat(c.value()).isFalse()
}
// Safety
@ -278,7 +282,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val c = constraintChecker.isAdvancedFilteringEnabled()
assertThat(c.reasonList).hasSize(1) // Safety
assertThat(c.mostLimitedReasonList).hasSize(1) // Safety
assertThat( c.value()).isFalse()
assertThat(c.value()).isFalse()
}
// SMB should limit
@ -286,7 +290,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
fun isSuperBolusEnabledTest() {
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
val c = constraintChecker.isSuperBolusEnabled()
assertThat( c.value()).isFalse() // SMB should limit
assertThat(c.value()).isFalse() // SMB should limit
}
// Safety & Objectives
@ -296,11 +300,11 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name)
// `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(Constraint(true))
// `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(ConstraintObject(true))
val c = constraintChecker.isSMBModeEnabled()
assertThat(c.reasonList).hasSize(3) // 2x Safety & Objectives
assertThat(c.mostLimitedReasonList).hasSize(3) // 2x Safety & Objectives
assertThat( c.value()).isFalse()
assertThat(c.value()).isFalse()
}
// applyBasalConstraints tests
@ -326,9 +330,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits
val d = constraintChecker.getMaxBasalAllowed(validProfile)
assertThat( d.value()).isWithin( 0.01).of(0.8)
assertThat(d.value()).isWithin(0.01).of(0.8)
assertThat(d.reasonList).hasSize(3)
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit")
assertThat(d.getMostLimitedReasons()).isEqualTo("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit")
}
@Test
@ -355,7 +359,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val i = constraintChecker.getMaxBasalPercentAllowed(validProfile)
assertThat(i.value()).isEqualTo(200)
assertThat(i.reasonList).hasSize(6)
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting max percent rate to 200% because of pump limit")
assertThat(i.getMostLimitedReasons()).isEqualTo("Safety: Limiting max percent rate to 200% because of pump limit")
}
// applyBolusConstraints tests
@ -380,9 +384,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits
val d = constraintChecker.getMaxBolusAllowed()
assertThat( d.value()).isWithin( 0.01).of(3.0)
assertThat(d.value()).isWithin(0.01).of(3.0)
assertThat(d.reasonList).hasSize(4) // 2x Safety & RS & R
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting bolus to 3.0 U because of max value in preferences")
assertThat(d.getMostLimitedReasons()).isEqualTo("Safety: Limiting bolus to 3.0 U because of max value in preferences")
}
// applyCarbsConstraints tests
@ -395,7 +399,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val i = constraintChecker.getMaxCarbsAllowed()
assertThat(i.value()).isEqualTo(48)
assertThat(i.reasonList).hasSize(1)
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting carbs to 48 g because of max value in preferences")
assertThat(i.getMostLimitedReasons()).isEqualTo("Safety: Limiting carbs to 48 g because of max value in preferences")
}
// applyMaxIOBConstraints tests
@ -410,9 +414,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits
val d = constraintChecker.getMaxIOBAllowed()
assertThat( d.value()).isWithin( 0.01).of(1.5)
assertThat(d.value()).isWithin(0.01).of(1.5)
assertThat(d.reasonList).hasSize(2)
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences")
assertThat(d.getMostLimitedReasons()).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences")
}
@Test
@ -426,8 +430,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits
val d = constraintChecker.getMaxIOBAllowed()
assertThat( d.value()).isWithin( 0.01).of(3.0)
assertThat(d.value()).isWithin(0.01).of(3.0)
assertThat(d.reasonList).hasSize(2)
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences")
assertThat(d.getMostLimitedReasons()).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences")
}
}

View file

@ -3,12 +3,12 @@ package info.nightscout.plugins.safety
import com.google.common.truth.Truth.assertThat
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
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.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profiling.Profiler
@ -29,7 +29,7 @@ import org.mockito.Mockito.`when`
class SafetyPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Mock lateinit var glimpPlugin: GlimpPlugin
@Mock lateinit var profiler: Profiler
@ -43,7 +43,13 @@ class SafetyPluginTest : TestBaseWithProfile() {
private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
private val injector = HasAndroidInjector { AndroidInjector { } }
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
private val pumpDescription = PumpDescription()
@BeforeEach
@ -86,9 +92,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
@Test
fun pumpDescriptionShouldLimitLoopInvocation() {
pumpDescription.isTempBasalCapable = false
var c = Constraint(true)
c = safetyPlugin.isLoopInvocationAllowed(c)
assertThat(c.getReasons(aapsLogger)).isEqualTo("Safety: Pump is not temp basal capable")
val c = safetyPlugin.isLoopInvocationAllowed(ConstraintObject(true, injector))
assertThat(c.getReasons()).isEqualTo("Safety: Pump is not temp basal capable")
assertThat(c.value()).isFalse()
}
@ -96,47 +101,42 @@ class SafetyPluginTest : TestBaseWithProfile() {
fun disabledEngineeringModeShouldLimitClosedLoop() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name)
`when`(config.isEngineeringModeOrRelease()).thenReturn(false)
var c = Constraint(true)
c = safetyPlugin.isClosedLoopAllowed(c)
assertThat(c.getReasons(aapsLogger)).contains("Running dev version. Closed loop is disabled.")
val c = safetyPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
assertThat(c.getReasons()).contains("Running dev version. Closed loop is disabled.")
assertThat(c.value()).isFalse()
}
@Test
fun setOpenLoopInPreferencesShouldLimitClosedLoop() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name)
var c = Constraint(true)
c = safetyPlugin.isClosedLoopAllowed(c)
assertThat(c.getReasons(aapsLogger)).contains("Closed loop mode disabled in preferences")
val c = safetyPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
assertThat(c.getReasons()).contains("Closed loop mode disabled in preferences")
assertThat(c.value()).isFalse()
}
@Test
fun notEnabledSMBInPreferencesDisablesSMB() {
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false)
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(true))
var c = Constraint(true)
c = openAPSSMBPlugin.isSMBModeEnabled(c)
assertThat(c.getReasons(aapsLogger)).contains("SMB disabled in preferences")
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(ConstraintObject(true, injector))
val c = openAPSSMBPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
assertThat(c.getReasons()).contains("SMB disabled in preferences")
assertThat(c.value()).isFalse()
}
@Test
fun openLoopPreventsSMB() {
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(true)
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(false))
var c = Constraint(true)
c = safetyPlugin.isSMBModeEnabled(c)
assertThat(c.getReasons(aapsLogger)).contains("SMB not allowed in open loop mode")
`when`(constraintChecker.isClosedLoopAllowed()).thenReturn(ConstraintObject(false, injector))
val c = safetyPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
assertThat(c.getReasons()).contains("SMB not allowed in open loop mode")
assertThat(c.value()).isFalse()
}
@Test
fun bgSourceShouldPreventSMBAlways() {
`when`(activePlugin.activeBgSource).thenReturn(glimpPlugin)
var c = Constraint(true)
c = safetyPlugin.isAdvancedFilteringEnabled(c)
assertThat(c.getReasons(aapsLogger)).isEqualTo("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering")
val c = safetyPlugin.isAdvancedFilteringEnabled(ConstraintObject(true, injector))
assertThat(c.getReasons()).isEqualTo("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering")
assertThat(c.value()).isFalse()
}
@ -146,24 +146,26 @@ class SafetyPluginTest : TestBaseWithProfile() {
`when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsama_current_basal_safety_multiplier, 4.0)).thenReturn(4.0)
`when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsama_max_daily_safety_multiplier, 3.0)).thenReturn(3.0)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
val c = Constraint(Constants.REALLYHIGHBASALRATE)
val c = ConstraintObject(Double.MAX_VALUE, injector)
safetyPlugin.applyBasalConstraints(c, validProfile)
assertThat(c.value()).isWithin(0.01).of(2.0)
assertThat(c.getReasons(aapsLogger)).isEqualTo(
assertThat(c.getReasons()).isEqualTo(
"""
Safety: Limiting max basal rate to 2.00 U/h because of hard limit
""".trimIndent())
assertThat(c.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting max basal rate to 2.00 U/h because of hard limit")
""".trimIndent()
)
assertThat(c.getMostLimitedReasons()).isEqualTo("Safety: Limiting max basal rate to 2.00 U/h because of hard limit")
}
@Test
fun doNotAllowNegativeBasalRate() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
val d = Constraint(-0.5)
val d = ConstraintObject(-0.5, injector)
safetyPlugin.applyBasalConstraints(d, validProfile)
assertThat(d.value()).isWithin(0.01).of(0.0)
assertThat(d.getReasons(aapsLogger)).isEqualTo(
"Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value")
assertThat(d.getReasons()).isEqualTo(
"Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value"
)
}
@Test
@ -173,19 +175,20 @@ class SafetyPluginTest : TestBaseWithProfile() {
`when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsama_current_basal_safety_multiplier, 4.0)).thenReturn(4.0)
`when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsama_max_daily_safety_multiplier, 3.0)).thenReturn(3.0)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
val i = Constraint(Constants.REALLYHIGHPERCENTBASALRATE)
val i = ConstraintObject(Int.MAX_VALUE, injector)
safetyPlugin.applyBasalPercentConstraints(i, validProfile)
assertThat(i.value()).isEqualTo(200)
assertThat(i.getReasons(aapsLogger)).isEqualTo(
assertThat(i.getReasons()).isEqualTo(
"""
Safety: Percent rate 1111111% recalculated to 11111.11 U/h with current basal 1.00 U/h
Safety: Percent rate 2147483647% recalculated to 21474836.47 U/h with current basal 1.00 U/h
Safety: Limiting max basal rate to 2.00 U/h because of hard limit
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()
)
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo(
"Safety: Limiting max percent rate to 200% because of pump limit")
assertThat(i.getMostLimitedReasons()).isEqualTo(
"Safety: Limiting max percent rate to 200% because of pump limit"
)
}
@Test
@ -196,57 +199,58 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
`when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsama_max_daily_safety_multiplier, 3.0)).thenReturn(3.0)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
val i = Constraint(Constants.REALLYHIGHBASALRATE)
val i = ConstraintObject(Double.MAX_VALUE, injector)
openAPSSMBPlugin.applyBasalConstraints(i, validProfile)
assertThat(i.value()).isWithin(0.01).of(1.0)
assertThat(i.getReasons(aapsLogger)).isEqualTo(
assertThat(i.getReasons()).isEqualTo(
"""
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())
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences")
""".trimIndent()
)
assertThat(i.getMostLimitedReasons()).isEqualTo("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences")
}
@Test
fun doNotAllowNegativePercentBasalRate() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
val i = Constraint(-22)
val i = ConstraintObject(-22, injector)
safetyPlugin.applyBasalPercentConstraints(i, validProfile)
assertThat(i.value()).isEqualTo(0)
assertThat(i.getReasons(aapsLogger)).isEqualTo(
assertThat(i.getReasons()).isEqualTo(
"""
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())
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting max percent rate to 0% because of pump limit")
""".trimIndent()
)
assertThat(i.getMostLimitedReasons()).isEqualTo("Safety: Limiting max percent rate to 0% because of pump limit")
}
@Test
fun bolusAmountShouldBeLimited() {
`when`(sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
var d = Constraint(Constants.REALLYHIGHBOLUS)
d = safetyPlugin.applyBolusConstraints(d)
val d = safetyPlugin.applyBolusConstraints(ConstraintObject(Double.MAX_VALUE, injector))
assertThat(d.value()).isWithin(0.01).of(3.0)
assertThat(d.getReasons(aapsLogger)).isEqualTo(
assertThat(d.getReasons()).isEqualTo(
"""
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())
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting bolus to 3.0 U because of max value in preferences")
""".trimIndent()
)
assertThat(d.getMostLimitedReasons()).isEqualTo("Safety: Limiting bolus to 3.0 U because of max value in preferences")
}
@Test
fun doNotAllowNegativeBolusAmount() {
`when`(sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0)
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
var d = Constraint(-22.0)
d = safetyPlugin.applyBolusConstraints(d)
val d = safetyPlugin.applyBolusConstraints(ConstraintObject(-22.0, injector))
assertThat(d.value()).isWithin(0.01).of(0.0)
assertThat(d.getReasons(aapsLogger)).isEqualTo("Safety: Limiting bolus to 0.0 U because of it must be positive value")
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting bolus to 0.0 U because of it must be positive value")
assertThat(d.getReasons()).isEqualTo("Safety: Limiting bolus to 0.0 U because of it must be positive value")
assertThat(d.getMostLimitedReasons()).isEqualTo("Safety: Limiting bolus to 0.0 U because of it must be positive value")
}
@Test
@ -255,15 +259,15 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit
`when`(sp.getInt(info.nightscout.core.utils.R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48)
// Negative carbs not allowed
var i = Constraint(-22)
var i: Constraint<Int> = ConstraintObject(-22, injector)
safetyPlugin.applyCarbsConstraints(i)
assertThat(i.value()).isEqualTo(0)
assertThat(i.getReasons(aapsLogger)).isEqualTo("Safety: Limiting carbs to 0 g because of it must be positive value")
assertThat(i.getReasons()).isEqualTo("Safety: Limiting carbs to 0 g because of it must be positive value")
// Apply all limits
i = safetyPlugin.applyCarbsConstraints(Constraint(Constants.REALLYHIGHCARBS))
i = safetyPlugin.applyCarbsConstraints(ConstraintObject(Int.MAX_VALUE, injector))
assertThat(i.value()).isEqualTo(48)
assertThat(i.getReasons(aapsLogger)).isEqualTo("Safety: Limiting carbs to 48 g because of max value in preferences")
assertThat(i.getReasons()).isEqualTo("Safety: Limiting carbs to 48 g because of max value in preferences")
}
@Test
@ -278,24 +282,24 @@ 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("teenage")
// Apply all limits
var d = Constraint(Constants.REALLYHIGHIOB)
var d: Constraint<Double> = ConstraintObject(Double.MAX_VALUE, injector)
d = safetyPlugin.applyMaxIOBConstraints(d)
assertThat(d.value()).isWithin(0.01).of(HardLimits.MAX_IOB_LGS)
assertThat(d.getReasons(aapsLogger)).isEqualTo("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend")
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend")
assertThat(d.getReasons()).isEqualTo("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend")
assertThat(d.getMostLimitedReasons()).isEqualTo("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend")
// Apply all limits
d = Constraint(Constants.REALLYHIGHIOB)
d = ConstraintObject(Double.MAX_VALUE, injector)
val a = openAPSAMAPlugin.applyMaxIOBConstraints(d)
assertThat(a.value()).isWithin(0.01).of(1.5)
assertThat(d.getReasons(aapsLogger)).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences\nOpenAPSAMA: Limiting IOB to 7.0 U because of hard limit")
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences")
assertThat(d.getReasons()).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences\nOpenAPSAMA: Limiting IOB to 7.0 U because of hard limit")
assertThat(d.getMostLimitedReasons()).isEqualTo("OpenAPSAMA: Limiting IOB to 1.5 U because of max value in preferences")
// Apply all limits
d = Constraint(Constants.REALLYHIGHIOB)
d = ConstraintObject(Double.MAX_VALUE, injector)
val s = openAPSSMBPlugin.applyMaxIOBConstraints(d)
assertThat(s.value()).isWithin(0.01).of(3.0)
assertThat(d.getReasons(aapsLogger)).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences\nOpenAPSSMB: Limiting IOB to 22.0 U because of hard limit")
assertThat(d.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences")
assertThat(d.getReasons()).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences\nOpenAPSSMB: Limiting IOB to 22.0 U because of hard limit")
assertThat(d.getMostLimitedReasons()).isEqualTo("OpenAPSSMB: Limiting IOB to 3.0 U because of max value in preferences")
}
}

View file

@ -10,11 +10,6 @@ object Constants {
const val MMOLL_TO_MGDL = 18.0 // 18.0182;
const val MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL
const val defaultDIA = 5.0
const val REALLYHIGHBASALRATE = 1111111.0
const val REALLYHIGHPERCENTBASALRATE = 1111111
const val REALLYHIGHBOLUS = 1111111.0
const val REALLYHIGHCARBS = 1111111
const val REALLYHIGHIOB = 1111111.0
const val notificationID = 556677
// SMS COMMUNICATOR

View file

@ -1,115 +1,18 @@
package info.nightscout.interfaces.constraints
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
class Constraint<T : Comparable<T>>(private var value: T) {
private var originalValue: T
private val reasons: MutableList<String> = ArrayList()
private val mostLimiting: MutableList<String> = ArrayList()
fun value(): T {
return value
}
fun originalValue(): T {
return originalValue
}
fun set(aapsLogger: AAPSLogger, value: T): Constraint<T> {
this.value = value
originalValue = value
aapsLogger.debug(LTag.CONSTRAINTS, "Setting value $value")
return this
}
fun set(aapsLogger: AAPSLogger, value: T, reason: String, from: Any): Constraint<T> {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
addReason(reason, from)
addMostLimingReason(reason, from)
return this
}
fun setIfDifferent(aapsLogger: AAPSLogger, value: T, reason: String, from: Any): Constraint<T> {
if (this.value != value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of different value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
addReason(reason, from)
addMostLimingReason(reason, from)
}
return this
}
fun setIfSmaller(aapsLogger: AAPSLogger, value: T, reason: String, from: Any): Constraint<T> {
if (value < this.value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of smaller value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
mostLimiting.clear()
addMostLimingReason(reason, from)
}
if (value < originalValue) {
addReason(reason, from)
}
return this
}
fun setIfGreater(aapsLogger: AAPSLogger, value: T, reason: String, from: Any): Constraint<T> {
if (value > this.value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of greater value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
mostLimiting.clear()
addMostLimingReason(reason, from)
}
if (value > originalValue) {
addReason(reason, from)
}
return this
}
private fun translateFrom(from: Any): String {
return from.javaClass.simpleName.replace("Plugin", "")
}
fun addReason(reason: String, from: Any) {
reasons.add(translateFrom(from) + ": " + reason)
}
private fun addMostLimingReason(reason: String, from: Any) {
mostLimiting.add(translateFrom(from) + ": " + reason)
}
fun getReasons(aapsLogger: AAPSLogger): String {
val sb = StringBuilder()
for ((count, r) in reasons.withIndex()) {
if (count != 0) sb.append("\n")
sb.append(r)
}
aapsLogger.debug(LTag.CONSTRAINTS, "Limiting original value: $originalValue to $value. Reason: $sb")
return sb.toString()
}
interface Constraint<T : Comparable<T>> {
fun value(): T
fun originalValue(): T
fun set(value: T): Constraint<T>
fun set(value: T, reason: String, from: Any): Constraint<T>
fun setIfDifferent(value: T, reason: String, from: Any): Constraint<T>
fun setIfSmaller(value: T, reason: String, from: Any): Constraint<T>
fun setIfGreater(value: T, reason: String, from: Any): Constraint<T>
fun addReason(reason: String, from: Any)
fun getReasons(): String
val reasonList: List<String>
get() = reasons
fun getMostLimitedReasons(aapsLogger: AAPSLogger): String {
val sb = StringBuilder()
for ((count, r) in mostLimiting.withIndex()) {
if (count != 0) sb.append("\n")
sb.append(r)
}
aapsLogger.debug(LTag.CONSTRAINTS, "Limiting original value: $originalValue to $value. Reason: $sb")
return sb.toString()
}
fun getMostLimitedReasons(): String
val mostLimitedReasonList: List<String>
get() = mostLimiting
fun copyReasons(another: Constraint<*>) {
reasons.addAll(another.reasonList)
}
init {
originalValue = value
}
fun copyReasons(another: Constraint<*>)
}

View file

@ -1,58 +0,0 @@
package info.nightscout.interfaces.constraints
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.profile.Profile
/**
* Constraints interface
*
* Every function has a param from previous chained call
* Function can limit the value even more and add another reason of restriction
*
* see [info.nightscout.plugins.constraints.ConstraintsImpl]
* which iterates over all registered plugins with [Constraints] implemented
*
* @return updated parameter
*/
interface Constraints {
fun isLoopInvocationAllowed(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isClosedLoopAllowed(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isLgsAllowed(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isAutosensModeEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isSMBModeEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isDynIsfModeEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isUAMEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isAdvancedFilteringEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isSuperBolusEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun isAutomationEnabled(value: Constraint<Boolean> = Constraint(true)): Constraint<Boolean> = value
fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> = absoluteRate
fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> = percentRate
fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> = insulin
fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> = insulin
fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> = carbs
fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> = maxIob
/*
* Determine max values by walking through all constraints
*/
fun getMaxBasalAllowed(profile: Profile): Constraint<Double> =
applyBasalConstraints(Constraint(Constants.REALLYHIGHBASALRATE), profile)
fun getMaxBasalPercentAllowed(profile: Profile): Constraint<Int> =
applyBasalPercentConstraints(Constraint(Constants.REALLYHIGHPERCENTBASALRATE), profile)
fun getMaxBolusAllowed(): Constraint<Double> =
applyBolusConstraints(Constraint(Constants.REALLYHIGHBOLUS))
fun getMaxExtendedBolusAllowed(): Constraint<Double> =
applyExtendedBolusConstraints(Constraint(Constants.REALLYHIGHBOLUS))
fun getMaxCarbsAllowed(): Constraint<Int> =
applyCarbsConstraints(Constraint(Constants.REALLYHIGHCARBS))
fun getMaxIOBAllowed(): Constraint<Double> =
applyMaxIOBConstraints(Constraint(Constants.REALLYHIGHIOB))
}

View file

@ -0,0 +1,36 @@
package info.nightscout.interfaces.constraints
import info.nightscout.interfaces.profile.Profile
/**
* Constraints interface
*
* Every function has a param from previous chained call
* Function can limit the value even more and add another reason of restriction
*
* see [info.nightscout.plugins.constraints.ConstraintsCheckerImpl]
* which iterates over all registered plugins with [ConstraintsChecker] implemented
*/
interface ConstraintsChecker : PluginConstraints {
fun isLoopInvocationAllowed(): Constraint<Boolean>
fun isClosedLoopAllowed(): Constraint<Boolean>
fun isLgsAllowed(): Constraint<Boolean>
fun isAutosensModeEnabled(): Constraint<Boolean>
fun isSMBModeEnabled(): Constraint<Boolean>
fun isDynIsfModeEnabled(): Constraint<Boolean>
fun isUAMEnabled(): Constraint<Boolean>
fun isAdvancedFilteringEnabled(): Constraint<Boolean>
fun isSuperBolusEnabled(): Constraint<Boolean>
fun isAutomationEnabled(): Constraint<Boolean>
/*
* Determine max values by walking through all constraints
*/
fun getMaxBasalAllowed(profile: Profile): Constraint<Double>
fun getMaxBasalPercentAllowed(profile: Profile): Constraint<Int>
fun getMaxBolusAllowed(): Constraint<Double>
fun getMaxExtendedBolusAllowed(): Constraint<Double>
fun getMaxCarbsAllowed(): Constraint<Int>
fun getMaxIOBAllowed(): Constraint<Double>
}

View file

@ -0,0 +1,28 @@
package info.nightscout.interfaces.constraints
import info.nightscout.interfaces.profile.Profile
/**
* PluginConstraints interface
*
* Allows to every plugin implement own constraints
*/
interface PluginConstraints {
fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isDynIsfModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> = value
fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> = absoluteRate
fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> = percentRate
fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> = insulin
fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> = insulin
fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> = carbs
fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> = maxIob
}

View file

@ -20,6 +20,7 @@ dependencies {
implementation project(':core:utils')
testImplementation project(':app-wear-shared:shared-tests')
testImplementation project(':app-wear-shared:shared-impl')
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

View file

@ -0,0 +1,121 @@
package info.nightscout.core.constraints
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
class ConstraintObject<T : Comparable<T>>(private var value: T, injector: HasAndroidInjector) : Constraint<T> {
@Inject lateinit var aapsLogger: AAPSLogger
private var originalValue: T
private val reasons: MutableList<String> = ArrayList()
private val mostLimiting: MutableList<String> = ArrayList()
override fun value(): T {
return value
}
override fun originalValue(): T {
return originalValue
}
override fun set(value: T): Constraint<T> {
this.value = value
originalValue = value
aapsLogger.debug(LTag.CONSTRAINTS, "Setting value $value")
return this
}
override fun set(value: T, reason: String, from: Any): Constraint<T> {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
addReason(reason, from)
addMostLimingReason(reason, from)
return this
}
override fun setIfDifferent(value: T, reason: String, from: Any): Constraint<T> {
if (this.value != value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of different value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
addReason(reason, from)
addMostLimingReason(reason, from)
}
return this
}
override fun setIfSmaller(value: T, reason: String, from: Any): Constraint<T> {
if (value < this.value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of smaller value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
mostLimiting.clear()
addMostLimingReason(reason, from)
}
if (value < originalValue) {
addReason(reason, from)
}
return this
}
override fun setIfGreater(value: T, reason: String, from: Any): Constraint<T> {
if (value > this.value) {
aapsLogger.debug(LTag.CONSTRAINTS, "Setting because of greater value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]")
this.value = value
mostLimiting.clear()
addMostLimingReason(reason, from)
}
if (value > originalValue) {
addReason(reason, from)
}
return this
}
private fun translateFrom(from: Any): String {
return from.javaClass.simpleName.replace("Plugin", "")
}
override fun addReason(reason: String, from: Any) {
reasons.add(translateFrom(from) + ": " + reason)
}
private fun addMostLimingReason(reason: String, from: Any) {
mostLimiting.add(translateFrom(from) + ": " + reason)
}
override fun getReasons(): String {
val sb = StringBuilder()
for ((count, r) in reasons.withIndex()) {
if (count != 0) sb.append("\n")
sb.append(r)
}
aapsLogger.debug(LTag.CONSTRAINTS, "Limiting original value: $originalValue to $value. Reason: $sb")
return sb.toString()
}
override val reasonList: List<String>
get() = reasons
override fun getMostLimitedReasons(): String {
val sb = StringBuilder()
for ((count, r) in mostLimiting.withIndex()) {
if (count != 0) sb.append("\n")
sb.append(r)
}
aapsLogger.debug(LTag.CONSTRAINTS, "Limiting original value: $originalValue to $value. Reason: $sb")
return sb.toString()
}
override val mostLimitedReasonList: List<String>
get() = mostLimiting
override fun copyReasons(another: Constraint<*>) {
reasons.addAll(another.reasonList)
}
init {
injector.androidInjector().inject(this)
originalValue = value
}
}

View file

@ -4,6 +4,7 @@ import android.content.Context
import android.text.Spanned
import com.google.common.base.Joiner
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.highValueToUnitsToString
import info.nightscout.core.extensions.lowValueToUnitsToString
import info.nightscout.core.iob.round
@ -19,8 +20,7 @@ import info.nightscout.database.entities.ValueWithUnit
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.automation.Automation
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.GlucoseStatusProvider
@ -63,7 +63,7 @@ class BolusWizard @Inject constructor(
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var profileUtil: ProfileUtil
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var commandQueue: CommandQueue
@Inject lateinit var loop: Loop
@ -273,7 +273,7 @@ class BolusWizard @Inject constructor(
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
calculatedTotalInsulin = Round.roundTo(calculatedTotalInsulin, bolusStep)
insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(calculatedTotalInsulin)).value()
insulinAfterConstraints = constraintChecker.applyBolusConstraints(ConstraintObject(calculatedTotalInsulin, injector)).value()
aapsLogger.debug(this.toString())
return this

View file

@ -1,6 +1,8 @@
package info.nightscout.core.data
import info.nightscout.interfaces.constraints.Constraint
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
@ -11,41 +13,49 @@ import org.junit.jupiter.api.Test
*/
class ConstraintTest : TestBase() {
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@Test fun doTests() {
val b = Constraint(true)
val b = ConstraintObject(true, injector)
Assertions.assertEquals(true, b.value())
Assertions.assertEquals("", b.getReasons(aapsLogger))
Assertions.assertEquals("", b.getMostLimitedReasons(aapsLogger))
b.set(aapsLogger, false)
Assertions.assertEquals("", b.getReasons())
Assertions.assertEquals("", b.getMostLimitedReasons())
b.set(false)
Assertions.assertEquals(false, b.value())
Assertions.assertEquals("", b.getReasons(aapsLogger))
Assertions.assertEquals("", b.getMostLimitedReasons(aapsLogger))
b.set(aapsLogger, true, "Set true", this)
Assertions.assertEquals("", b.getReasons())
Assertions.assertEquals("", b.getMostLimitedReasons())
b.set(true, "Set true", this)
Assertions.assertEquals(true, b.value())
Assertions.assertEquals("ConstraintTest: Set true", b.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set true", b.getMostLimitedReasons(aapsLogger))
b.set(aapsLogger, false, "Set false", this)
Assertions.assertEquals("ConstraintTest: Set true", b.getReasons())
Assertions.assertEquals("ConstraintTest: Set true", b.getMostLimitedReasons())
b.set(false, "Set false", this)
Assertions.assertEquals(false, b.value())
Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getMostLimitedReasons(aapsLogger))
val d = Constraint(10.0)
d.set(aapsLogger, 5.0, "Set 5d", this)
Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getReasons())
Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getMostLimitedReasons())
val d = ConstraintObject(10.0, injector)
d.set(5.0, "Set 5d", this)
Assertions.assertEquals(5.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d", d.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons(aapsLogger))
d.setIfSmaller(aapsLogger, 6.0, "Set 6d", this)
Assertions.assertEquals("ConstraintTest: Set 5d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons())
d.setIfSmaller(6.0, "Set 6d", this)
Assertions.assertEquals(5.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons(aapsLogger))
d.setIfSmaller(aapsLogger, 4.0, "Set 4d", this)
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons())
d.setIfSmaller(4.0, "Set 4d", this)
Assertions.assertEquals(4.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons())
Assertions.assertEquals(10.0, d.originalValue(), 0.01)
d.setIfDifferent(aapsLogger, 7.0, "Set 7d", this)
d.setIfDifferent(7.0, "Set 7d", this)
Assertions.assertEquals(7.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getMostLimitedReasons())
Assertions.assertEquals(10.0, d.originalValue(), 0.01)
}

View file

@ -9,6 +9,7 @@ import info.nightscout.core.iob.plus
import info.nightscout.core.iob.round
import info.nightscout.interfaces.iob.IobTotal
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
@ -25,7 +26,7 @@ class IobTotalTest : TestBase() {
@BeforeEach
fun prepare() {
dateUtil = DateUtil(context)
dateUtil = DateUtilImpl(context)
now = dateUtil.now()
}

View file

@ -7,11 +7,10 @@ import info.nightscout.core.profile.ProfileSealed
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.rx.TestAapsSchedulers
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 info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.HardLimitsMock
import info.nightscout.sharedtests.TestBase
import info.nightscout.sharedtests.TestPumpPlugin
@ -37,7 +36,6 @@ class ProfileTest : TestBase() {
@Mock lateinit var sp: SP
private lateinit var hardLimits: HardLimits
private lateinit var rxBus: RxBus
private lateinit var dateUtil: DateUtil
private lateinit var testPumpPlugin: TestPumpPlugin
@ -59,8 +57,7 @@ class ProfileTest : TestBase() {
@BeforeEach
fun prepare() {
testPumpPlugin = TestPumpPlugin { AndroidInjector { } }
dateUtil = DateUtil(context)
rxBus = RxBus(TestAapsSchedulers(), aapsLogger)
dateUtil = DateUtilImpl(context)
hardLimits = HardLimitsMock(sp, rh)
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
`when`(rh.gs(info.nightscout.core.ui.R.string.profile_per_unit)).thenReturn("/U")

View file

@ -3,13 +3,13 @@ package info.nightscout.core.utils
import android.content.Context
import com.google.common.truth.Truth.assertThat
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.shared.utils.T
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.mockito.Mock
import org.mockito.Mockito.`when`
import java.util.Date
@ -41,45 +41,45 @@ class DateUtilTest : TestBase() {
@Test
fun fromISODateStringTest() {
Assertions.assertEquals(1511124634417L, DateUtil(context).fromISODateString("2017-11-19T22:50:34.417+0200"))
Assertions.assertEquals(1511124634000L, DateUtil(context).fromISODateString("2017-11-19T22:50:34+0200"))
Assertions.assertEquals(1512317365000L, DateUtil(context).fromISODateString("2017-12-03T16:09:25.000Z"))
Assertions.assertEquals(1513902750000L, DateUtil(context).fromISODateString("2017-12-22T00:32:30Z"))
Assertions.assertEquals(1511124634417L, DateUtilImpl(context).fromISODateString("2017-11-19T22:50:34.417+0200"))
Assertions.assertEquals(1511124634000L, DateUtilImpl(context).fromISODateString("2017-11-19T22:50:34+0200"))
Assertions.assertEquals(1512317365000L, DateUtilImpl(context).fromISODateString("2017-12-03T16:09:25.000Z"))
Assertions.assertEquals(1513902750000L, DateUtilImpl(context).fromISODateString("2017-12-22T00:32:30Z"))
}
@Test
fun toISOStringTest() {
Assertions.assertEquals("2017-12-22T00:32:30.000Z", DateUtil(context).toISOString(1513902750000L))
Assertions.assertEquals("2017-12-22T00:32:30.000Z", DateUtilImpl(context).toISOString(1513902750000L))
}
@Test fun secondsOfTheDayToMillisecondsTest() {
Assertions.assertTrue(Date(DateUtil(context).secondsOfTheDayToMilliseconds((T.hours(1).secs() + T.mins(1).secs() + 1).toInt())).toString().contains("01:01:00"))
Assertions.assertTrue(Date(DateUtilImpl(context).secondsOfTheDayToMilliseconds((T.hours(1).secs() + T.mins(1).secs() + 1).toInt())).toString().contains("01:01:00"))
}
@Test fun toSecondsTest() {
Assertions.assertEquals(3600, DateUtil(context).toSeconds("01:00").toLong())
Assertions.assertEquals(3600, DateUtil(context).toSeconds("01:00 a.m.").toLong())
Assertions.assertEquals(3600, DateUtil(context).toSeconds("01:00 AM").toLong())
Assertions.assertEquals(3600, DateUtilImpl(context).toSeconds("01:00").toLong())
Assertions.assertEquals(3600, DateUtilImpl(context).toSeconds("01:00 a.m.").toLong())
Assertions.assertEquals(3600, DateUtilImpl(context).toSeconds("01:00 AM").toLong())
}
@Test fun dateStringTest() {
assertThat(DateUtil(context).dateString(1513902750000L)).contains("22")
assertThat(DateUtilImpl(context).dateString(1513902750000L)).contains("22")
}
@Test fun timeStringTest() {
Assertions.assertTrue(DateUtil(context).timeString(1513902750000L).contains("32"))
Assertions.assertTrue(DateUtilImpl(context).timeString(1513902750000L).contains("32"))
}
@Test fun dateAndTimeStringTest() {
assertThat(DateUtil(context).dateAndTimeString(1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeString(1513902750000L)).contains("32")
assertThat(DateUtilImpl(context).dateAndTimeString(1513902750000L)).contains("22")
assertThat(DateUtilImpl(context).dateAndTimeString(1513902750000L)).contains("32")
}
@Test fun dateAndTimeRangeStringTest() {
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
}
/*
@ -90,6 +90,6 @@ class DateUtilTest : TestBase() {
*/
@Test fun timeFrameStringTest() {
`when`(rh.gs(info.nightscout.interfaces.R.string.shorthour)).thenReturn("h")
Assertions.assertEquals("(1h 1')", DateUtil(context).timeFrameString(T.hours(1).msecs() + T.mins(1).msecs(), rh))
Assertions.assertEquals("(1h 1')", DateUtilImpl(context).timeFrameString(T.hours(1).msecs() + T.mins(1).msecs(), rh))
}
}

View file

@ -12,6 +12,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.test.ext:junit-ktx:$androidx_junit_version"
androidTestImplementation "androidx.test:rules:$androidx_rules_version"
androidTestImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}

View file

@ -9,6 +9,7 @@ import android.text.Spanned
import androidx.appcompat.app.AppCompatActivity
import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.extensions.getCustomizedName
import info.nightscout.core.profile.ProfileSealed
@ -42,8 +43,7 @@ import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
import info.nightscout.implementation.queue.commands.CommandUpdateTime
import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
@ -85,7 +85,7 @@ class CommandQueueImplementation @Inject constructor(
private val rxBus: RxBus,
private val aapsSchedulers: AapsSchedulers,
private val rh: ResourceHelper,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val profileFunction: ProfileFunction,
private val activePlugin: ActivePlugin,
private val context: Context,
@ -310,8 +310,8 @@ class CommandQueueImplementation @Inject constructor(
removeAll(type)
}
// apply constraints
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
detailedBolusInfo.carbs = constraintChecker.applyCarbsConstraints(Constraint(detailedBolusInfo.carbs.toInt())).value().toDouble()
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(ConstraintObject(detailedBolusInfo.insulin, injector)).value()
detailedBolusInfo.carbs = constraintChecker.applyCarbsConstraints(ConstraintObject(detailedBolusInfo.carbs.toInt(), injector)).value().toDouble()
// add new command to queue
if (detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB) {
add(CommandSMBBolus(injector, detailedBolusInfo, callback))
@ -368,7 +368,7 @@ class CommandQueueImplementation @Inject constructor(
}
// remove all unfinished
removeAll(CommandType.TEMPBASAL)
val rateAfterConstraints = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
val rateAfterConstraints = constraintChecker.applyBasalConstraints(ConstraintObject(absoluteRate, injector), profile).value()
// add new command to queue
add(CommandTempBasalAbsolute(injector, rateAfterConstraints, durationInMinutes, enforceNew, profile, tbrType, callback))
notifyAboutNewCommand()
@ -383,7 +383,7 @@ class CommandQueueImplementation @Inject constructor(
}
// remove all unfinished
removeAll(CommandType.TEMPBASAL)
val percentAfterConstraints = constraintChecker.applyBasalPercentConstraints(Constraint(percent), profile).value()
val percentAfterConstraints = constraintChecker.applyBasalPercentConstraints(ConstraintObject(percent, injector), profile).value()
// add new command to queue
add(CommandTempBasalPercent(injector, percentAfterConstraints, durationInMinutes, enforceNew, profile, tbrType, callback))
notifyAboutNewCommand()
@ -396,7 +396,7 @@ class CommandQueueImplementation @Inject constructor(
callback?.result(executingNowError())?.run()
return false
}
val rateAfterConstraints = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
val rateAfterConstraints = constraintChecker.applyExtendedBolusConstraints(ConstraintObject(insulin, injector)).value()
// remove all unfinished
removeAll(CommandType.EXTENDEDBOLUS)
// add new command to queue

View file

@ -5,6 +5,7 @@ import android.os.Handler
import android.os.PowerManager
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.ValueWrapper
import info.nightscout.database.entities.Bolus
@ -16,8 +17,7 @@ import info.nightscout.implementation.queue.commands.CommandLoadHistory
import info.nightscout.implementation.queue.commands.CommandTempBasalPercent
import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
@ -50,7 +50,7 @@ import java.util.Calendar
class CommandQueueImplementationTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var powerManager: PowerManager
@Mock lateinit var repository: AppRepository
@Mock lateinit var uiInteraction: UiInteraction
@ -63,7 +63,7 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
rxBus: RxBus,
aapsSchedulers: AapsSchedulers,
rh: ResourceHelper,
constraintChecker: Constraints,
constraintChecker: ConstraintsChecker,
profileFunction: ProfileFunction,
activePlugin: ActivePlugin,
context: Context,
@ -88,6 +88,9 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is Command) {
it.aapsLogger = aapsLogger
it.rh = rh
@ -140,14 +143,14 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
)
`when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0)
val bolusConstraint = ConstraintObject(0.0, injector)
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint)
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(bolusConstraint)
val carbsConstraint = Constraint(0)
val carbsConstraint = ConstraintObject(0, injector)
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(carbsConstraint)
val rateConstraint = Constraint(0.0)
val rateConstraint = ConstraintObject(0.0, injector)
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint)
val percentageConstraint = Constraint(0)
val percentageConstraint = ConstraintObject(0, injector)
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint)
`when`(rh.gs(info.nightscout.core.ui.R.string.connectiontimedout)).thenReturn("Connection timed out")
`when`(rh.gs(info.nightscout.core.ui.R.string.format_insulin_units)).thenReturn("%1\$.2f U")

View file

@ -4,11 +4,11 @@ import android.content.Context
import android.os.PowerManager
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.impl.AppRepository
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpDescription
@ -25,7 +25,7 @@ import org.mockito.Mockito
class QueueThreadTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var powerManager: PowerManager
@Mock lateinit var repository: AppRepository
@Mock lateinit var androidPermission: AndroidPermission
@ -34,6 +34,9 @@ class QueueThreadTest : TestBaseWithProfile() {
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is Command) {
it.aapsLogger = aapsLogger
it.rh = rh
@ -64,14 +67,14 @@ class QueueThreadTest : TestBaseWithProfile() {
Mockito.`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
Mockito.`when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0)
val bolusConstraint = ConstraintObject(0.0, injector)
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint)
Mockito.`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(bolusConstraint)
val carbsConstraint = Constraint(0)
val carbsConstraint = ConstraintObject(0, injector)
Mockito.`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(carbsConstraint)
val rateConstraint = Constraint(0.0)
val rateConstraint = ConstraintObject(0.0, injector)
Mockito.`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint)
val percentageConstraint = Constraint(0)
val percentageConstraint = ConstraintObject(0, injector)
Mockito.`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject()))
.thenReturn(percentageConstraint)
Mockito.`when`(rh.gs(ArgumentMatchers.eq(info.nightscout.core.ui.R.string.temp_basal_absolute), anyObject(), anyObject())).thenReturn("TEMP BASAL %1\$.2f U/h %2\$d min")

View file

@ -8,12 +8,11 @@ import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.IobTotal
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.pump.defs.PumpDescription
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.Test
import org.mockito.Mock
@ -24,7 +23,7 @@ class BolusWizardTest : TestBaseWithProfile() {
private val pumpBolusStep = 0.1
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var loop: Loop
@Mock lateinit var autosensDataStore: AutosensDataStore
@ -34,7 +33,7 @@ class BolusWizardTest : TestBaseWithProfile() {
if (it is BolusWizard) {
it.aapsLogger = aapsLogger
it.rh = rh
it.rxBus = RxBus(aapsSchedulers, aapsLogger)
it.rxBus = rxBus
it.profileFunction = profileFunction
it.constraintChecker = constraintChecker
it.activePlugin = activePlugin
@ -113,7 +112,7 @@ class BolusWizardTest : TestBaseWithProfile() {
useAlarm = false
)
val bolusForBg54 = bw.calculatedTotalInsulin
assertThat(bolusForBg54).isWithin( 0.01).of(bolusForBg42)
assertThat(bolusForBg54).isWithin(0.01).of(bolusForBg42)
}
@Test

View file

@ -103,7 +103,7 @@ import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
import info.nightscout.core.events.EventNewNotification;
import info.nightscout.interfaces.Config;
import info.nightscout.interfaces.constraints.Constraint;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.PluginConstraints;
import info.nightscout.interfaces.notifications.Notification;
import info.nightscout.interfaces.plugin.OwnDatabasePlugin;
import info.nightscout.interfaces.plugin.PluginDescription;
@ -134,9 +134,10 @@ import info.nightscout.shared.utils.DateUtil;
import info.nightscout.shared.utils.T;
@Singleton
public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight, Constraints, OwnDatabasePlugin,
public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight, PluginConstraints, OwnDatabasePlugin,
InsightConnectionService.StateCallback {
public static final String ALERT_CHANNEL_ID = "AAPS-InsightAlert";
private final AAPSLogger aapsLogger;
private final RxBus rxBus;
private final ResourceHelper rh;
@ -148,13 +149,12 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
private final InsightDbHelper insightDbHelper;
private final PumpSync pumpSync;
private final InsightDatabase insightDatabase;
public static final String ALERT_CHANNEL_ID = "AAPS-InsightAlert";
private final PumpDescription pumpDescription;
private final Object $bolusLock = new Object[0];
public double lastBolusAmount = 0;
public long lastBolusTimestamp = 0L;
private InsightAlertService alertService;
private InsightConnectionService connectionService;
private long timeOffset;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
@ -174,8 +174,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
connectionService = null;
}
};
private final Object $bolusLock = new Object[0];
private long timeOffset;
private int bolusID;
private boolean bolusCancelled;
private BasalProfile activeBasalProfile;
@ -192,8 +191,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
private List<ActiveBolus> activeBoluses;
private boolean statusLoaded;
private TBROverNotificationBlock tbrOverNotificationBlock;
public double lastBolusAmount = 0;
public long lastBolusTimestamp = 0L;
@Inject
public LocalInsightPlugin(
@ -1589,22 +1586,22 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
@NonNull @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, @NonNull Profile profile) {
percentRate.setIfGreater(getAapsLogger(), 0, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
percentRate.setIfGreater(0, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().getMaxTempPercent(), rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
return percentRate;
}
@NonNull @Override
public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) {
if (!limitsFetched) return insulin;
insulin.setIfSmaller(getAapsLogger(), maximumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, maximumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
insulin.setIfSmaller(maximumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, maximumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
if (insulin.value() < minimumBolusAmount) {
//TODO: Add function to Constraints or use different approach
// This only works if the interface of the InsightPlugin is called last.
// If not, another constraint could theoretically set the value between 0 and minimumBolusAmount
insulin.set(getAapsLogger(), 0d, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, minimumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
insulin.set(0d, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, minimumBolusAmount, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this);
}
return insulin;
}

View file

@ -9,7 +9,7 @@ import info.nightscout.core.utils.HtmlHelper
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.interfaces.aps.APSResult
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.iob.IobTotal
import info.nightscout.interfaces.plugin.ActivePlugin
@ -34,7 +34,7 @@ import kotlin.math.max
open class APSResultObject @Inject constructor(val injector: HasAndroidInjector) : APSResult {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var sp: SP
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var iobCobCalculator: IobCobCalculator
@ -74,12 +74,12 @@ open class APSResultObject @Inject constructor(val injector: HasAndroidInjector)
val pump = activePlugin.activePump
if (isChangeRequested) {
// rate
var ret: String = if (rate == 0.0 && duration == 0) "${rh.gs(info.nightscout.core.ui.R.string.cancel_temp)} "
else if (rate == -1.0) "${rh.gs(info.nightscout.core.ui.R.string.let_temp_basal_run)}\n"
else if (usePercent) "${rh.gs(info.nightscout.core.ui.R.string.rate)}: ${decimalFormatter.to2Decimal(percent.toDouble())}% (${decimalFormatter.to2Decimal(percent * pump.baseBasalRate / 100.0)} U/h) " +
"${rh.gs(info.nightscout.core.ui.R.string.duration)}: ${decimalFormatter.to2Decimal(duration.toDouble())} min "
else "${rh.gs(info.nightscout.core.ui.R.string.rate)}: ${decimalFormatter.to2Decimal(rate)} U/h (${decimalFormatter.to2Decimal(rate / pump.baseBasalRate * 100)}%) " +
"${rh.gs(info.nightscout.core.ui.R.string.duration)}: ${decimalFormatter.to2Decimal(duration.toDouble())} min "
var ret: String = if (rate == 0.0 && duration == 0) "${rh.gs(R.string.cancel_temp)} "
else if (rate == -1.0) "${rh.gs(R.string.let_temp_basal_run)}\n"
else if (usePercent) "${rh.gs(R.string.rate)}: ${decimalFormatter.to2Decimal(percent.toDouble())}% (${decimalFormatter.to2Decimal(percent * pump.baseBasalRate / 100.0)} U/h) " +
"${rh.gs(R.string.duration)}: ${decimalFormatter.to2Decimal(duration.toDouble())} min "
else "${rh.gs(R.string.rate)}: ${decimalFormatter.to2Decimal(rate)} U/h (${decimalFormatter.to2Decimal(rate / pump.baseBasalRate * 100)}%) " +
"${rh.gs(R.string.duration)}: ${decimalFormatter.to2Decimal(duration.toDouble())} min "
// smb
if (smb != 0.0) ret += "SMB: ${decimalFormatter.toPumpSupportedBolus(smb, activePlugin.activePump.pumpDescription.bolusStep)} "
if (isCarbsRequired) {
@ -92,7 +92,7 @@ open class APSResultObject @Inject constructor(val injector: HasAndroidInjector)
}
return if (isCarbsRequired) {
carbsRequiredText
} else rh.gs(info.nightscout.core.ui.R.string.nochangerequested)
} else rh.gs(R.string.nochangerequested)
}
override fun toSpanned(): Spanned {
@ -100,17 +100,17 @@ open class APSResultObject @Inject constructor(val injector: HasAndroidInjector)
if (isChangeRequested) {
// rate
var ret: String =
if (rate == 0.0 && duration == 0) rh.gs(info.nightscout.core.ui.R.string.cancel_temp) + "<br>" else if (rate == -1.0) rh.gs(info.nightscout.core.ui.R.string.let_temp_basal_run) + "<br>" else if (usePercent) "<b>" + rh.gs(
info.nightscout.core.ui.R.string.rate
if (rate == 0.0 && duration == 0) rh.gs(R.string.cancel_temp) + "<br>" else if (rate == -1.0) rh.gs(R.string.let_temp_basal_run) + "<br>" else if (usePercent) "<b>" + rh.gs(
R.string.rate
) + "</b>: " + decimalFormatter.to2Decimal(
percent.toDouble()
) + "% " +
"(" + decimalFormatter.to2Decimal(percent * pump.baseBasalRate / 100.0) + " U/h)<br>" +
"<b>" + rh.gs(info.nightscout.core.ui.R.string.duration) + "</b>: " + decimalFormatter.to2Decimal(duration.toDouble()) + " min<br>" else "<b>" + rh.gs(info.nightscout.core.ui.R.string.rate) + "</b>: " + decimalFormatter.to2Decimal(
"<b>" + rh.gs(R.string.duration) + "</b>: " + decimalFormatter.to2Decimal(duration.toDouble()) + " min<br>" else "<b>" + rh.gs(R.string.rate) + "</b>: " + decimalFormatter.to2Decimal(
rate
) + " U/h " +
"(" + decimalFormatter.to2Decimal(rate / pump.baseBasalRate * 100.0) + "%) <br>" +
"<b>" + rh.gs(info.nightscout.core.ui.R.string.duration) + "</b>: " + decimalFormatter.to2Decimal(duration.toDouble()) + " min<br>"
"<b>" + rh.gs(R.string.duration) + "</b>: " + decimalFormatter.to2Decimal(duration.toDouble()) + " min<br>"
// smb
if (smb != 0.0) ret += "<b>" + "SMB" + "</b>: " + decimalFormatter.toPumpSupportedBolus(smb, activePlugin.activePump.pumpDescription.bolusStep) + "<br>"

View file

@ -150,7 +150,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider {
binding.mealdata.text = jsonFormatter.format(determineBasalAdapter.mealDataParam)
binding.scriptdebugdata.text = determineBasalAdapter.scriptDebug.replace("\\s+".toRegex(), " ")
openAPSPlugin.lastAPSResult?.inputConstraints?.let {
binding.constraints.text = it.getReasons(aapsLogger)
binding.constraints.text = it.getReasons()
}
}
if (openAPSPlugin.lastAPSRun != 0L) {

View file

@ -12,12 +12,13 @@ import android.view.ViewGroup
import androidx.core.view.MenuCompat
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.pump.toHtml
import info.nightscout.core.utils.HtmlHelper
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.utils.DecimalFormatter
import info.nightscout.plugins.aps.R
import info.nightscout.plugins.aps.databinding.LoopFragmentBinding
@ -44,6 +45,7 @@ class LoopFragment : DaggerFragment(), MenuProvider {
@Inject lateinit var loop: Loop
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var decimalFormatter: DecimalFormatter
@Inject lateinit var injector: HasAndroidInjector
@Suppress("PrivatePropertyName")
private val ID_MENU_RUN = 501
@ -150,12 +152,12 @@ class LoopFragment : DaggerFragment(), MenuProvider {
var constraints =
it.constraintsProcessed?.let { constraintsProcessed ->
val allConstraints = Constraint(0.0)
val allConstraints = ConstraintObject(0.0, injector)
constraintsProcessed.rateConstraint?.let { rateConstraint -> allConstraints.copyReasons(rateConstraint) }
constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) }
allConstraints.getMostLimitedReasons(aapsLogger)
allConstraints.getMostLimitedReasons()
} ?: ""
constraints += loop.closedLoopEnabled?.getReasons(aapsLogger) ?: ""
constraints += loop.closedLoopEnabled?.getReasons() ?: ""
binding.constraints.text = constraints
binding.swipeRefresh.isRefreshing = false
}

View file

@ -14,6 +14,7 @@ import android.os.SystemClock
import androidx.core.app.NotificationCompat
import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.extensions.convertedToAbsolute
import info.nightscout.core.extensions.convertedToPercent
@ -36,7 +37,7 @@ import info.nightscout.interfaces.aps.APSResult
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.aps.Loop.LastRun
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.notifications.Notification
@ -91,7 +92,7 @@ class LoopPlugin @Inject constructor(
private val rxBus: RxBus,
private val sp: SP,
private val config: Config,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
rh: ResourceHelper,
private val profileFunction: ProfileFunction,
private val context: Context,
@ -230,7 +231,7 @@ class LoopPlugin @Inject constructor(
if (!loopEnabled.value()) {
val message = """
${rh.gs(info.nightscout.core.ui.R.string.loop_disabled)}
${loopEnabled.getReasons(aapsLogger)}
${loopEnabled.getReasons()}
""".trimIndent()
aapsLogger.debug(LTag.APS, message)
rxBus.send(EventLoopSetLastRunGui(message))
@ -274,11 +275,11 @@ class LoopPlugin @Inject constructor(
// check rate for constraints
val resultAfterConstraints = apsResult.newAndClone(injector)
resultAfterConstraints.rateConstraint = Constraint(resultAfterConstraints.rate)
resultAfterConstraints.rateConstraint = ConstraintObject(resultAfterConstraints.rate, injector)
resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint!!, profile).value()
resultAfterConstraints.percentConstraint = Constraint(resultAfterConstraints.percent)
resultAfterConstraints.percentConstraint = ConstraintObject(resultAfterConstraints.percent, injector)
resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint!!, profile).value()
resultAfterConstraints.smbConstraint = Constraint(resultAfterConstraints.smb)
resultAfterConstraints.smbConstraint = ConstraintObject(resultAfterConstraints.smb, injector)
resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value()
// safety check for multiple SMBs

View file

@ -7,7 +7,7 @@ import info.nightscout.core.extensions.plannedRemainingMinutes
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.DetermineBasalAdapter
import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.iob.IobTotal
@ -43,7 +43,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
private val injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator
@ -107,7 +107,8 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
makeParam(profile, rhino, scope),
makeParam(autosensData, rhino, scope),
makeParam(mealData, rhino, scope),
setTempBasalFunctionsObj)
setTempBasalFunctionsObj
)
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
scriptDebug = LoggerCallback.scriptDebug

View file

@ -3,6 +3,7 @@ package info.nightscout.plugins.aps.openAPSAMA
import android.content.Context
import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.target
import info.nightscout.core.utils.MidnightUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
@ -12,7 +13,8 @@ import info.nightscout.interfaces.aps.APS
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.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
@ -46,7 +48,7 @@ class OpenAPSAMAPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
private val rxBus: RxBus,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
rh: ResourceHelper,
private val profileFunction: ProfileFunction,
private val context: Context,
@ -69,7 +71,7 @@ class OpenAPSAMAPlugin @Inject constructor(
.preferencesId(R.xml.pref_openapsama)
.description(R.string.description_ama),
aapsLogger, rh, injector
), APS, Constraints {
), APS, PluginConstraints {
// last values
override var lastAPSRun: Long = 0
@ -114,7 +116,7 @@ class OpenAPSAMAPlugin @Inject constructor(
aapsLogger.debug(LTag.APS, rh.gs(R.string.openapsma_no_glucose_data))
return
}
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
val inputConstraints = ConstraintObject(0.0, injector) // fake. only for collecting all results
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
inputConstraints.copyReasons(it)
}.value()
@ -237,8 +239,8 @@ class OpenAPSAMAPlugin @Inject constructor(
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
if (isEnabled()) {
val maxIobPref: Double = sp.getDouble(R.string.key_openapsma_max_iob, 1.5)
maxIob.setIfSmaller(aapsLogger, maxIobPref, rh.gs(R.string.limiting_iob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), rh.gs(R.string.limiting_iob, hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
maxIob.setIfSmaller(maxIobPref, rh.gs(R.string.limiting_iob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
maxIob.setIfSmaller(hardLimits.maxIobAMA(), rh.gs(R.string.limiting_iob, hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
}
return maxIob
}
@ -250,27 +252,26 @@ class OpenAPSAMAPlugin @Inject constructor(
maxBasal = profile.getMaxDailyBasal()
absoluteRate.addReason(rh.gs(R.string.increasing_max_basal), this)
}
absoluteRate.setIfSmaller(aapsLogger, maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
absoluteRate.setIfSmaller(maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
// Check percentRate but absolute rate too, because we know real current basal in pump
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.getBasal() * 100) / 100
absoluteRate.setIfSmaller(
aapsLogger,
maxFromBasalMultiplier,
rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromBasalMultiplier, rh.gs(R.string.max_basal_multiplier)),
this
)
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
val maxFromDaily = floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.max_daily_basal_multiplier)), this)
absoluteRate.setIfSmaller(maxFromDaily, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.max_daily_basal_multiplier)), this)
}
return absoluteRate
}
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val enabled = sp.getBoolean(R.string.key_openapsama_use_autosens, false)
if (!enabled) value.set(aapsLogger, false, rh.gs(R.string.autosens_disabled_in_preferences), this)
if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this)
return value
}
}

View file

@ -7,7 +7,7 @@ import info.nightscout.core.extensions.plannedRemainingMinutes
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.DetermineBasalAdapter
import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.iob.IobTotal
@ -42,7 +42,7 @@ import javax.inject.Inject
class DetermineBasalAdapterSMBJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapter {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator

View file

@ -4,6 +4,7 @@ import android.content.Context
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.target
import info.nightscout.core.utils.MidnightUtils
import info.nightscout.database.ValueWrapper
@ -14,7 +15,8 @@ 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.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
@ -44,7 +46,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
private val rxBus: RxBus,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
rh: ResourceHelper,
private val profileFunction: ProfileFunction,
val context: Context,
@ -69,7 +71,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
.description(R.string.description_smb)
.setDefault(),
aapsLogger, rh, injector
), APS, Constraints {
), APS, PluginConstraints {
// DynamicISF specific
var tdd1D: Double? = null
@ -77,7 +79,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
var tddLast24H: Double? = null
var tddLast4H: Double? = null
var tddLast8to4H: Double? = null
var dynIsfEnabled: Constraint<Boolean> = Constraint(false)
var dynIsfEnabled: Constraint<Boolean> = ConstraintObject(false, injector)
// last values
override var lastAPSRun: Long = 0
@ -129,7 +131,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
return
}
val inputConstraints = Constraint(0.0) // fake. only for collecting all results
val inputConstraints = ConstraintObject(0.0, injector) // fake. only for collecting all results
val maxBasal = constraintChecker.getMaxBasalAllowed(profile).also {
inputConstraints.copyReasons(it)
}.value()
@ -207,19 +209,19 @@ open class OpenAPSSMBPlugin @Inject constructor(
val iobArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
profiler.log(LTag.APS, "calculateIobArrayInDia()", startPart)
startPart = System.currentTimeMillis()
val smbAllowed = Constraint(!tempBasalFallback).also {
val smbAllowed = ConstraintObject(!tempBasalFallback, injector).also {
constraintChecker.isSMBModeEnabled(it)
inputConstraints.copyReasons(it)
}
val advancedFiltering = Constraint(!tempBasalFallback).also {
val advancedFiltering = ConstraintObject(!tempBasalFallback, injector).also {
constraintChecker.isAdvancedFilteringEnabled(it)
inputConstraints.copyReasons(it)
}
val uam = Constraint(true).also {
val uam = ConstraintObject(true, injector).also {
constraintChecker.isUAMEnabled(it)
inputConstraints.copyReasons(it)
}
dynIsfEnabled = Constraint(true).also {
dynIsfEnabled = ConstraintObject(true, injector).also {
constraintChecker.isDynIsfModeEnabled(it)
inputConstraints.copyReasons(it)
}
@ -239,12 +241,12 @@ open class OpenAPSSMBPlugin @Inject constructor(
if (tdd1D == null || tdd7D == null || tddLast4H == null || tddLast8to4H == null || tddLast24H == null) {
inputConstraints.copyReasons(
Constraint(false).also {
it.set(aapsLogger, false, rh.gs(R.string.fallback_smb_no_tdd), this)
ConstraintObject(false, injector).also {
it.set(false, rh.gs(R.string.fallback_smb_no_tdd), this)
}
)
inputConstraints.copyReasons(
Constraint(false).apply { set(aapsLogger, true, "tdd1D=$tdd1D tdd7D=$tdd7D tddLast4H=$tddLast4H tddLast8to4H=$tddLast8to4H tddLast24H=$tddLast24H", this) }
ConstraintObject(false, injector).apply { set(true, "tdd1D=$tdd1D tdd7D=$tdd7D tddLast4H=$tddLast4H tddLast8to4H=$tddLast8to4H tddLast24H=$tddLast24H", this) }
)
}
@ -293,15 +295,15 @@ open class OpenAPSSMBPlugin @Inject constructor(
}
override fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
value.set(aapsLogger, false)
value.set(false)
return value
}
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
if (isEnabled()) {
val maxIobPref: Double = sp.getDouble(R.string.key_openapssmb_max_iob, 3.0)
maxIob.setIfSmaller(aapsLogger, maxIobPref, rh.gs(R.string.limiting_iob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), rh.gs(R.string.limiting_iob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
maxIob.setIfSmaller(maxIobPref, rh.gs(R.string.limiting_iob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
maxIob.setIfSmaller(hardLimits.maxIobSMB(), rh.gs(R.string.limiting_iob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
}
return maxIob
}
@ -313,39 +315,38 @@ open class OpenAPSSMBPlugin @Inject constructor(
maxBasal = profile.getMaxDailyBasal()
absoluteRate.addReason(rh.gs(R.string.increasing_max_basal), this)
}
absoluteRate.setIfSmaller(aapsLogger, maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
absoluteRate.setIfSmaller(maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
// Check percentRate but absolute rate too, because we know real current basal in pump
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.getBasal() * 100) / 100
absoluteRate.setIfSmaller(
aapsLogger,
maxFromBasalMultiplier,
rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromBasalMultiplier, rh.gs(R.string.max_basal_multiplier)),
this
)
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
val maxFromDaily = floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.max_daily_basal_multiplier)), this)
absoluteRate.setIfSmaller(maxFromDaily, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.max_daily_basal_multiplier)), this)
}
return absoluteRate
}
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val enabled = sp.getBoolean(R.string.key_use_smb, false)
if (!enabled) value.set(aapsLogger, false, rh.gs(R.string.smb_disabled_in_preferences), this)
if (!enabled) value.set(false, rh.gs(R.string.smb_disabled_in_preferences), this)
return value
}
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val enabled = sp.getBoolean(R.string.key_use_uam, false)
if (!enabled) value.set(aapsLogger, false, rh.gs(R.string.uam_disabled_in_preferences), this)
if (!enabled) value.set(false, rh.gs(R.string.uam_disabled_in_preferences), this)
return value
}
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val enabled = sp.getBoolean(R.string.key_openapsama_use_autosens, false)
if (!enabled) value.set(aapsLogger, false, rh.gs(R.string.autosens_disabled_in_preferences), this)
if (!enabled) value.set(false, rh.gs(R.string.autosens_disabled_in_preferences), this)
return value
}

View file

@ -6,7 +6,7 @@ import info.nightscout.annotations.OpenForTesting
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.aps.DetermineBasalAdapter
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
@ -32,7 +32,7 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
rxBus: RxBus,
constraintChecker: Constraints,
constraintChecker: ConstraintsChecker,
rh: ResourceHelper,
profileFunction: ProfileFunction,
context: Context,

View file

@ -2,11 +2,11 @@ package info.nightscout.plugins.aps.loop
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.JsonHelper.safeGetDouble
import info.nightscout.database.entities.TemporaryBasal
import info.nightscout.interfaces.aps.APSResult
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.pump.defs.PumpType
import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.Assertions
@ -18,11 +18,11 @@ import org.mockito.Mockito.`when`
class APSResultTest : TestBaseWithProfile() {
@Mock lateinit var constraints: Constraints
@Mock lateinit var constraintsChecker: ConstraintsChecker
private val injector = HasAndroidInjector { AndroidInjector { } }
private var closedLoopEnabled = Constraint(false)
private var closedLoopEnabled = ConstraintObject(false, injector)
private fun APSResult.percent(percent: Int): APSResult {
this.percent = percent
@ -55,7 +55,7 @@ class APSResultTest : TestBaseWithProfile() {
val apsResult = info.nightscout.plugins.aps.APSResultObject { AndroidInjector { } }
.also {
it.aapsLogger = aapsLogger
it.constraintChecker = constraints
it.constraintChecker = constraintsChecker
it.sp = sp
it.activePlugin = activePlugin
it.iobCobCalculator = iobCobCalculator
@ -70,7 +70,7 @@ class APSResultTest : TestBaseWithProfile() {
apsResult.usePercent(true)
// closed loop mode return original request
closedLoopEnabled.set(aapsLogger, true)
closedLoopEnabled.set(true)
`when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(false)
Assertions.assertEquals(false, apsResult.isChangeRequested)
@ -78,7 +78,7 @@ class APSResultTest : TestBaseWithProfile() {
Assertions.assertEquals(true, apsResult.isChangeRequested)
// open loop
closedLoopEnabled.set(aapsLogger, false)
closedLoopEnabled.set(false)
// no change requested
`when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(false)
@ -184,7 +184,7 @@ class APSResultTest : TestBaseWithProfile() {
apsResult.usePercent(false)
// open loop
closedLoopEnabled.set(aapsLogger, false)
closedLoopEnabled.set(false)
// request 100% when no temp is running
`when`(iobCobCalculator.getTempBasalIncludingConvertedExtended(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(true).rate(1.0).duration(30)
@ -296,7 +296,7 @@ class APSResultTest : TestBaseWithProfile() {
val apsResult = info.nightscout.plugins.aps.APSResultObject { AndroidInjector { } }
.also {
it.aapsLogger = aapsLogger
it.constraintChecker = constraints
it.constraintChecker = constraintsChecker
it.sp = sp
it.activePlugin = activePlugin
it.iobCobCalculator = iobCobCalculator
@ -309,11 +309,11 @@ class APSResultTest : TestBaseWithProfile() {
}
@Test fun jsonTest() {
closedLoopEnabled.set(aapsLogger, true)
closedLoopEnabled.set(true)
val apsResult = info.nightscout.plugins.aps.APSResultObject { AndroidInjector { } }
.also {
it.aapsLogger = aapsLogger
it.constraintChecker = constraints
it.constraintChecker = constraintsChecker
it.sp = sp
it.activePlugin = activePlugin
it.iobCobCalculator = iobCobCalculator
@ -328,7 +328,7 @@ class APSResultTest : TestBaseWithProfile() {
@BeforeEach
fun prepare() {
`when`(constraints.isClosedLoopAllowed(anyObject())).thenReturn(closedLoopEnabled)
`when`(constraintsChecker.isClosedLoopAllowed(anyObject())).thenReturn(closedLoopEnabled)
`when`(sp.getDouble(ArgumentMatchers.anyInt(), ArgumentMatchers.anyDouble())).thenReturn(30.0)
`when`(profileFunction.getProfile()).thenReturn(validProfile)
}

View file

@ -26,6 +26,7 @@ dependencies {
implementation project(':database:impl')
testImplementation project(':app-wear-shared:shared-tests')
testImplementation project(':app-wear-shared:shared-impl')
testImplementation project(':implementation')
testImplementation project(':plugins:main')

View file

@ -49,7 +49,7 @@ import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.automation.Automation
import info.nightscout.interfaces.automation.AutomationEvent
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -87,7 +87,7 @@ class AutomationPlugin @Inject constructor(
private val fabricPrivacy: FabricPrivacy,
private val loop: Loop,
private val rxBus: RxBus,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers,
private val config: Config,
@ -244,7 +244,7 @@ class AutomationPlugin @Inject constructor(
}
val enabled = constraintChecker.isAutomationEnabled()
if (!enabled.value()) {
executionLog.add(enabled.getMostLimitedReasons(aapsLogger))
executionLog.add(enabled.getMostLimitedReasons())
rxBus.send(EventAutomationUpdateGui())
commonEventsEnabled = false
}
@ -413,7 +413,7 @@ class AutomationPlugin @Inject constructor(
}
/**
* Generate reminder via [info.nightscout.interfaces.utils.TimerUtil]
* Generate reminder via [info.nightscout.automation.ui.TimerUtil]
*
* @param seconds seconds to the future
*/

View file

@ -10,7 +10,6 @@ import info.nightscout.automation.triggers.TriggerConnectorTest
import info.nightscout.automation.triggers.TriggerDummy
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.aps.Loop
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.sharedtests.TestBase
import org.json.JSONObject
@ -36,7 +35,7 @@ class AutomationEventTest : TestBase() {
it.loopPlugin = loopPlugin
it.rh = rh
it.configBuilder = configBuilder
it.rxBus = RxBus(aapsSchedulers, aapsLogger)
it.rxBus = rxBus
}
}
}

View file

@ -10,13 +10,13 @@ import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
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 info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
@ -32,8 +32,7 @@ class BolusTimerImplTest : TestBase() {
@Mock lateinit var sp: SP
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var loop: Loop
@Mock lateinit var rxBus: RxBus
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var config: Config
@Mock lateinit var locationServiceHelper: LocationServiceHelper
@Mock lateinit var activePlugin: ActivePlugin
@ -49,16 +48,17 @@ class BolusTimerImplTest : TestBase() {
}
}
private lateinit var dateUtil: DateUtil
private lateinit var automationPlugin: AutomationPlugin
@BeforeEach
fun init() {
Mockito.`when`(rh.gs(anyInt())).thenReturn("")
Mockito.`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
dateUtil = DateUtil(context)
automationPlugin = AutomationPlugin(injector, rh, context, sp, fabricPrivacy, loop, rxBus, constraintChecker, aapsLogger, aapsSchedulers, config, locationServiceHelper, dateUtil,
activePlugin, timerUtil)
dateUtil = DateUtilImpl(context)
automationPlugin = AutomationPlugin(
injector, rh, context, sp, fabricPrivacy, loop, rxBus, constraintChecker, aapsLogger, aapsSchedulers, config, locationServiceHelper, dateUtil,
activePlugin, timerUtil
)
}
@Test

View file

@ -10,13 +10,13 @@ import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
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 info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
@ -33,8 +33,7 @@ class CarbTimerImplTest : TestBase() {
@Mock lateinit var sp: SP
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var loop: Loop
@Mock lateinit var rxBus: RxBus
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var config: Config
@Mock lateinit var locationServiceHelper: LocationServiceHelper
@Mock lateinit var activePlugin: ActivePlugin
@ -57,7 +56,7 @@ class CarbTimerImplTest : TestBase() {
fun init() {
Mockito.`when`(rh.gs(anyInt())).thenReturn("")
Mockito.`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
dateUtil = DateUtil(context)
dateUtil = DateUtilImpl(context)
timerUtil = TimerUtil(context)
automationPlugin = AutomationPlugin(
injector, rh, context, sp, fabricPrivacy, loop, rxBus, constraintChecker, aapsLogger, aapsSchedulers, config, locationServiceHelper, dateUtil,

View file

@ -9,7 +9,6 @@ import info.nightscout.automation.ui.TimerUtil
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.Callback
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import info.nightscout.sharedtests.TestBase
@ -23,7 +22,6 @@ import org.mockito.Mockito.`when`
class ActionAlarmTest : TestBase() {
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var rxBus: RxBus
@Mock lateinit var context: Context
@Mock lateinit var dateUtil: DateUtil
@Mock lateinit var config: Config

View file

@ -26,7 +26,7 @@ class ActionNotificationTest : TestBase() {
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var context: Context
@Mock lateinit var rxBus: RxBus
@Mock lateinit var rxBusMocked: RxBus
@Mock lateinit var repository: AppRepository
private lateinit var sut: ActionNotification
@ -34,7 +34,7 @@ class ActionNotificationTest : TestBase() {
AndroidInjector {
if (it is ActionNotification) {
it.rh = rh
it.rxBus = rxBus
it.rxBus = rxBusMocked
it.repository = repository
}
if (it is PumpEnactResult) {
@ -78,7 +78,7 @@ class ActionNotificationTest : TestBase() {
Assertions.assertTrue(result.success)
}
})
Mockito.verify(rxBus, Mockito.times(2)).send(anyObject())
Mockito.verify(rxBusMocked, Mockito.times(2)).send(anyObject())
//Mockito.verify(repository, Mockito.times(1)).runTransaction(any(Transaction::class.java))
}

View file

@ -3,29 +3,24 @@ package info.nightscout.automation.actions
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.automation.triggers.Trigger
import info.nightscout.database.entities.DeviceStatus
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.entities.OfflineEvent
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.interfaces.smsCommunicator.SmsCommunicator
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock
@ -45,7 +40,7 @@ ActionsTestBase : TestBaseWithProfile() {
private var suspended = false
override var lastRun: Loop.LastRun? = Loop.LastRun()
override var closedLoopEnabled: Constraint<Boolean>? = Constraint(true)
override var closedLoopEnabled: Constraint<Boolean>? = ConstraintObject(true, injector)
override val isSuspended: Boolean = suspended
override val isLGS: Boolean = false
override val isSuperBolus: Boolean = false
@ -174,6 +169,9 @@ ActionsTestBase : TestBaseWithProfile() {
it.rh = rh
it.aapsLogger = aapsLogger
}
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}

View file

@ -8,7 +8,6 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock
@ -31,7 +30,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
AndroidInjector {
if (it is Trigger) {
it.aapsLogger = aapsLogger
it.rxBus = RxBus(aapsSchedulers, aapsLogger)
it.rxBus = rxBus
it.rh = rh
it.profileFunction = profileFunction
it.sp = sp

View file

@ -1,109 +1,135 @@
package info.nightscout.plugins.constraints
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin) : Constraints {
class ConstraintsCheckerImpl @Inject constructor(
private val activePlugin: ActivePlugin,
val injector: HasAndroidInjector
) : ConstraintsChecker {
override fun isLoopInvocationAllowed(): Constraint<Boolean> = isLoopInvocationAllowed(ConstraintObject(true, injector))
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isLoopInvocationAllowed(value)
}
return value
}
override fun isClosedLoopAllowed(): Constraint<Boolean> = isClosedLoopAllowed(ConstraintObject(true, injector))
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isClosedLoopAllowed(value)
}
return value
}
override fun isLgsAllowed(): Constraint<Boolean> = isLgsAllowed(ConstraintObject(true, injector))
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isLgsAllowed(value)
}
return value
}
override fun isAutosensModeEnabled(): Constraint<Boolean> = isAutosensModeEnabled(ConstraintObject(true, injector))
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isAutosensModeEnabled(value)
}
return value
}
override fun isSMBModeEnabled(): Constraint<Boolean> = isSMBModeEnabled(ConstraintObject(true, injector))
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isSMBModeEnabled(value)
}
return value
}
override fun isDynIsfModeEnabled(): Constraint<Boolean> = isDynIsfModeEnabled(ConstraintObject(true, injector))
override fun isDynIsfModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isDynIsfModeEnabled(value)
}
return value
}
override fun isUAMEnabled(): Constraint<Boolean> = isUAMEnabled(ConstraintObject(true, injector))
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isUAMEnabled(value)
}
return value
}
override fun isAdvancedFilteringEnabled(): Constraint<Boolean> = isAdvancedFilteringEnabled(ConstraintObject(true, injector))
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isAdvancedFilteringEnabled(value)
}
return value
}
override fun isSuperBolusEnabled(): Constraint<Boolean> = isSuperBolusEnabled(ConstraintObject(true, injector))
override fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isSuperBolusEnabled(value)
}
return value
}
override fun isAutomationEnabled(): Constraint<Boolean> = isAutomationEnabled(ConstraintObject(true, injector))
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.applyBasalConstraints(absoluteRate, profile)
}
@ -111,9 +137,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constrain = p as Constraints
val constrain = p as PluginConstraints
if (!p.isEnabled()) continue
constrain.applyBasalPercentConstraints(percentRate, profile)
}
@ -121,9 +147,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constrain = p as Constraints
val constrain = p as PluginConstraints
if (!p.isEnabled()) continue
constrain.applyBolusConstraints(insulin)
}
@ -131,9 +157,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constrain = p as Constraints
val constrain = p as PluginConstraints
if (!p.isEnabled()) continue
constrain.applyExtendedBolusConstraints(insulin)
}
@ -141,9 +167,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constrain = p as Constraints
val constrain = p as PluginConstraints
if (!p.isEnabled()) continue
constrain.applyCarbsConstraints(carbs)
}
@ -151,9 +177,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constrain = p as Constraints
val constrain = p as PluginConstraints
if (!p.isEnabled()) continue
constrain.applyMaxIOBConstraints(maxIob)
}
@ -161,12 +187,34 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
}
override fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)
val constraintsPlugins = activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)
for (p in constraintsPlugins) {
val constraint = p as Constraints
val constraint = p as PluginConstraints
if (!p.isEnabled()) continue
constraint.isAutomationEnabled(value)
}
return value
}
/*
* Determine max values by walking through all constraints
*/
override fun getMaxBasalAllowed(profile: Profile): Constraint<Double> =
applyBasalConstraints(ConstraintObject(Double.MAX_VALUE, injector), profile)
override fun getMaxBasalPercentAllowed(profile: Profile): Constraint<Int> =
applyBasalPercentConstraints(ConstraintObject(Int.MAX_VALUE, injector), profile)
override fun getMaxBolusAllowed(): Constraint<Double> =
applyBolusConstraints(ConstraintObject(Double.MAX_VALUE, injector))
override fun getMaxExtendedBolusAllowed(): Constraint<Double> =
applyExtendedBolusConstraints(ConstraintObject(Double.MAX_VALUE, injector))
override fun getMaxCarbsAllowed(): Constraint<Int> =
applyCarbsConstraints(ConstraintObject(Int.MAX_VALUE, injector))
override fun getMaxIOBAllowed(): Constraint<Double> =
applyMaxIOBConstraints(ConstraintObject(Double.MAX_VALUE, injector))
}

View file

@ -5,7 +5,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
@ -48,7 +48,7 @@ class BgQualityCheckPlugin @Inject constructor(
.showInList(false)
.pluginName(R.string.bg_quality),
aapsLogger, rh, injector
), Constraints, BgQualityCheck {
), PluginConstraints, BgQualityCheck {
private var disposable: CompositeDisposable = CompositeDisposable()
@ -71,7 +71,7 @@ class BgQualityCheckPlugin @Inject constructor(
// Fallback to LGS if BG values are doubled
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (state == BgQualityCheck.State.DOUBLED)
maxIob.set(aapsLogger, 0.0, "Doubled values in BGSource", this)
maxIob.set(0.0, "Doubled values in BGSource", this)
else
maxIob

View file

@ -3,9 +3,9 @@ package info.nightscout.plugins.constraints.di
import dagger.Binds
import dagger.Module
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils
import info.nightscout.plugins.constraints.ConstraintsImpl
import info.nightscout.plugins.constraints.ConstraintsCheckerImpl
import info.nightscout.plugins.constraints.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.plugins.constraints.versionChecker.VersionCheckerUtilsImpl
@ -24,6 +24,6 @@ abstract class PluginsConstraintsModule {
@Binds fun bindVersionCheckerUtils(versionCheckerUtils: VersionCheckerUtilsImpl): VersionCheckerUtils
@Binds fun bindBgQualityCheck(bgQualityCheck: BgQualityCheckPlugin): BgQualityCheck
@Binds fun bindsConstraints(constraintsImpl: ConstraintsImpl): Constraints
@Binds fun bindsConstraintChecker(constraintsCheckerImpl: ConstraintsCheckerImpl): ConstraintsChecker
}
}

View file

@ -3,7 +3,7 @@ package info.nightscout.plugins.constraints.dstHelper
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
@ -35,7 +35,7 @@ class DstHelperPlugin @Inject constructor(
.showInList(false)
.pluginName(R.string.dst_plugin_name),
aapsLogger, rh, injector
), Constraints {
), PluginConstraints {
companion object {
@ -74,7 +74,7 @@ class DstHelperPlugin @Inject constructor(
} else {
aapsLogger.debug(LTag.CONSTRAINTS, "Loop already suspended")
}
value.set(aapsLogger, false, "DST in last 3 hours.", this)
value.set(false, "DST in last 3 hours.", this)
}
return value
}

View file

@ -3,7 +3,6 @@ package info.nightscout.plugins.constraints.objectives
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.constraints.Objectives.Companion.AUTOSENS_OBJECTIVE
import info.nightscout.interfaces.constraints.Objectives.Companion.AUTO_OBJECTIVE
@ -12,6 +11,7 @@ import info.nightscout.interfaces.constraints.Objectives.Companion.FIRST_OBJECTI
import info.nightscout.interfaces.constraints.Objectives.Companion.MAXBASAL_OBJECTIVE
import info.nightscout.interfaces.constraints.Objectives.Companion.MAXIOB_ZERO_CL_OBJECTIVE
import info.nightscout.interfaces.constraints.Objectives.Companion.SMB_OBJECTIVE
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -54,7 +54,7 @@ class ObjectivesPlugin @Inject constructor(
.shortName(R.string.objectives_shortname)
.description(R.string.description_objectives),
aapsLogger, rh, injector
), Constraints, Objectives {
), PluginConstraints, Objectives {
var objectives: MutableList<Objective> = ArrayList()
@ -112,49 +112,49 @@ class ObjectivesPlugin @Inject constructor(
*/
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[FIRST_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, FIRST_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, FIRST_OBJECTIVE + 1), this)
return value
}
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[MAXBASAL_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, MAXBASAL_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, MAXBASAL_OBJECTIVE + 1), this)
return value
}
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
return value
}
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[AUTOSENS_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, AUTOSENS_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, AUTOSENS_OBJECTIVE + 1), this)
return value
}
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[SMB_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, SMB_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, SMB_OBJECTIVE + 1), this)
return value
}
override fun isDynIsfModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[DYN_ISF_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, DYN_ISF_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, DYN_ISF_OBJECTIVE + 1), this)
return value
}
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
if (objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted && !objectives[MAXIOB_ZERO_CL_OBJECTIVE].isAccomplished)
maxIob.set(aapsLogger, 0.0, rh.gs(R.string.objectivenotfinished, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
maxIob.set(0.0, rh.gs(R.string.objectivenotfinished, MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
return maxIob
}
override fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
if (!objectives[AUTO_OBJECTIVE].isStarted)
value.set(aapsLogger, false, rh.gs(R.string.objectivenotstarted, AUTO_OBJECTIVE + 1), this)
value.set(false, rh.gs(R.string.objectivenotstarted, AUTO_OBJECTIVE + 1), this)
return value
}

View file

@ -1,9 +1,8 @@
package info.nightscout.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.plugins.constraints.R
@ -14,12 +13,13 @@ class Objective4(injector: HasAndroidInjector) : Objective(injector, "maxbasal",
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var activePlugin: ActivePlugin
init {
tasks.add(
object : Task(this, R.string.objectives_maxbasal_gate) {
override fun isCompleted(): Boolean {
val profile = profileFunction.getProfile() ?: return false
val maxBasalSet = (activePlugin.activeAPS as Constraints).applyBasalConstraints(Constraint(Constants.REALLYHIGHBASALRATE), profile)
val maxBasalSet = (activePlugin.activeAPS as PluginConstraints).applyBasalConstraints(ConstraintObject(Double.MAX_VALUE, injector), profile)
val maxDailyBasal = profile.getMaxDailyBasal()
return maxBasalSet.value() > 2.8 * maxDailyBasal
}

View file

@ -1,7 +1,7 @@
package info.nightscout.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.plugins.constraints.R
import info.nightscout.plugins.constraints.safety.SafetyPlugin
import info.nightscout.shared.utils.T
@ -17,7 +17,7 @@ class Objective5(injector: HasAndroidInjector) : Objective(injector, "maxiobzero
tasks.add(
object : Task(this, R.string.closedmodeenabled) {
override fun isCompleted(): Boolean {
val closedLoopEnabled = Constraint(true)
val closedLoopEnabled = ConstraintObject(true, injector)
safetyPlugin.isClosedLoopAllowed(closedLoopEnabled)
return closedLoopEnabled.value()
}

View file

@ -2,7 +2,7 @@ package info.nightscout.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.plugins.constraints.R
import info.nightscout.shared.utils.T
import javax.inject.Inject
@ -10,7 +10,7 @@ import javax.inject.Inject
@Suppress("SpellCheckingInspection")
class Objective6(injector: HasAndroidInjector) : Objective(injector, "maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate) {
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
init {
tasks.add(MinimumDurationTask(this, T.days(1).msecs()))

View file

@ -4,7 +4,7 @@ import android.content.Context
import android.os.Build
import com.scottyab.rootbeer.RootBeer
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -22,13 +22,13 @@ class PhoneCheckerPlugin @Inject constructor(
private val context: Context
) : PluginBase(
PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.pluginName(R.string.phone_checker),
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.pluginName(R.string.phone_checker),
aapsLogger, rh, injector
), Constraints {
), PluginConstraints {
var phoneRooted: Boolean = false
var devMode: Boolean = false
@ -36,8 +36,10 @@ class PhoneCheckerPlugin @Inject constructor(
val manufacturer: String = Build.MANUFACTURER
private fun isDevModeEnabled(): Boolean {
return android.provider.Settings.Secure.getInt(context.contentResolver,
android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0
return android.provider.Settings.Secure.getInt(
context.contentResolver,
android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0
) != 0
}
override fun onStart() {

View file

@ -1,6 +1,7 @@
package info.nightscout.plugins.constraints.safety
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.extensions.putDouble
import info.nightscout.core.utils.extensions.putInt
import info.nightscout.core.utils.extensions.putString
@ -10,7 +11,8 @@ import info.nightscout.core.utils.extensions.storeString
import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.constraints.Safety
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.notifications.Notification
@ -39,7 +41,7 @@ class SafetyPlugin @Inject constructor(
aapsLogger: AAPSLogger,
rh: ResourceHelper,
private val sp: SP,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val activePlugin: ActivePlugin,
private val hardLimits: HardLimits,
private val config: Config,
@ -56,57 +58,57 @@ class SafetyPlugin @Inject constructor(
.pluginName(R.string.safety)
.preferencesId(R.xml.pref_safety),
aapsLogger, rh, injector
), Constraints, Safety {
), PluginConstraints, Safety {
/**
* Constraints interface
*/
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (!activePlugin.activePump.pumpDescription.isTempBasalCapable) value.set(aapsLogger, false, rh.gs(R.string.pumpisnottempbasalcapable), this)
if (!activePlugin.activePump.pumpDescription.isTempBasalCapable) value.set(false, rh.gs(R.string.pumpisnottempbasalcapable), this)
return value
}
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
val mode = ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name))
if (mode == ApsMode.OPEN) value.set(aapsLogger, false, rh.gs(R.string.closedmodedisabledinpreferences), this)
if (mode == ApsMode.OPEN) value.set(false, rh.gs(R.string.closedmodedisabledinpreferences), this)
if (!config.isEngineeringModeOrRelease()) {
if (value.value()) {
uiInteraction.addNotification(Notification.TOAST_ALARM, rh.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL)
}
value.set(aapsLogger, false, rh.gs(R.string.closed_loop_disabled_on_dev_branch), this)
value.set(false, rh.gs(R.string.closed_loop_disabled_on_dev_branch), this)
}
val pump = activePlugin.activePump
if (!pump.isFakingTempsByExtendedBoluses && iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) {
value.set(aapsLogger, false, rh.gs(R.string.closed_loop_disabled_with_eb), this)
value.set(false, rh.gs(R.string.closed_loop_disabled_with_eb), this)
}
return value
}
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val closedLoop = constraintChecker.isClosedLoopAllowed()
if (!closedLoop.value()) value.set(aapsLogger, false, rh.gs(R.string.smbnotallowedinopenloopmode), this)
if (!closedLoop.value()) value.set(false, rh.gs(R.string.smbnotallowedinopenloopmode), this)
return value
}
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val bgSource = activePlugin.activeBgSource
if (!bgSource.advancedFilteringSupported()) value.set(aapsLogger, false, rh.gs(R.string.smbalwaysdisabled), this)
if (!bgSource.advancedFilteringSupported()) value.set(false, rh.gs(R.string.smbalwaysdisabled), this)
return value
}
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
absoluteRate.setIfGreater(aapsLogger, 0.0, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
absoluteRate.setIfGreater(0.0, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
absoluteRate.setIfSmaller(hardLimits.maxBasal(), rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
// check for pump max
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, pumpLimit, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
absoluteRate.setIfSmaller(pumpLimit, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, pumpLimit, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
}
// do rounding
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
absoluteRate.set(aapsLogger, Round.roundTo(absoluteRate.value(), pump.pumpDescription.tempAbsoluteStep))
absoluteRate.set(Round.roundTo(absoluteRate.value(), pump.pumpDescription.tempAbsoluteStep))
}
return absoluteRate
}
@ -119,52 +121,58 @@ class SafetyPlugin @Inject constructor(
currentBasal
) + " U/h", this
)
val absoluteConstraint = Constraint(absoluteRate)
val absoluteConstraint = ConstraintObject(absoluteRate, injector)
applyBasalConstraints(absoluteConstraint, profile)
percentRate.copyReasons(absoluteConstraint)
val pump = activePlugin.activePump
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
percentRate.set(aapsLogger, percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
percentRateAfterConst =
if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble())
.toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
percentRate.set(percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, pumpLimit, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
percentRate.setIfSmaller(pumpLimit.toInt(), rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, pumpLimit, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
}
return percentRate
}
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
insulin.setIfGreater(0.0, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
val maxBolus = sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(info.nightscout.core.ui.R.string.limitingbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
insulin.setIfSmaller(maxBolus, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(hardLimits.maxBolus(), rh.gs(info.nightscout.core.ui.R.string.limitingbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(info.nightscout.core.ui.R.string.pumplimit), this)
insulin.setIfDifferent(rounded, rh.gs(info.nightscout.core.ui.R.string.pumplimit), this)
return insulin
}
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingextendedbolus, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
insulin.setIfGreater(0.0, rh.gs(R.string.limitingextendedbolus, 0.0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
val maxBolus = sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(R.string.limitingextendedbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(R.string.limitingextendedbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
insulin.setIfSmaller(maxBolus, rh.gs(R.string.limitingextendedbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
insulin.setIfSmaller(hardLimits.maxBolus(), rh.gs(R.string.limitingextendedbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(info.nightscout.core.ui.R.string.pumplimit), this)
insulin.setIfDifferent(rounded, rh.gs(info.nightscout.core.ui.R.string.pumplimit), this)
return insulin
}
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
carbs.setIfGreater(aapsLogger, 0, rh.gs(R.string.limitingcarbs, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
carbs.setIfGreater(0, rh.gs(R.string.limitingcarbs, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
val maxCarbs = sp.getInt(info.nightscout.core.utils.R.string.key_treatmentssafety_maxcarbs, 48)
carbs.setIfSmaller(aapsLogger, maxCarbs, rh.gs(R.string.limitingcarbs, maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
carbs.setIfSmaller(maxCarbs, rh.gs(R.string.limitingcarbs, maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
return carbs
}
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> {
val apsMode = ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name))
if (apsMode == ApsMode.LGS) maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, rh.gs(info.nightscout.core.ui.R.string.limiting_iob, HardLimits.MAX_IOB_LGS, rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend)), this)
if (apsMode == ApsMode.LGS) maxIob.setIfSmaller(
HardLimits.MAX_IOB_LGS,
rh.gs(info.nightscout.core.ui.R.string.limiting_iob, HardLimits.MAX_IOB_LGS, rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend)),
this
)
return maxIob
}

View file

@ -6,7 +6,7 @@ import android.os.Handler
import android.os.HandlerThread
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -54,7 +54,7 @@ class SignatureVerifierPlugin @Inject constructor(
.showInList(false)
.pluginName(R.string.signature_verifier),
aapsLogger, rh, injector
), Constraints {
), PluginConstraints {
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
@ -88,7 +88,7 @@ class SignatureVerifierPlugin @Inject constructor(
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
if (hasIllegalSignature()) {
showNotification()
value.set(aapsLogger, false)
value.set(false)
}
if (shouldDownloadCerts()) {
handler.post {

View file

@ -6,7 +6,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -34,13 +34,13 @@ class StorageConstraintPlugin @Inject constructor(
.showInList(false)
.pluginName(R.string.storage),
aapsLogger, rh, injector
), Constraints {
), PluginConstraints {
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
val diskFree = availableInternalMemorySize()
if (diskFree < Constants.MINIMUM_FREE_SPACE) {
aapsLogger.debug(LTag.CONSTRAINTS, "Closed loop disabled. Internal storage free (Mb):$diskFree")
value.set(aapsLogger, false, rh.gs(R.string.disk_full, Constants.MINIMUM_FREE_SPACE), this)
value.set(false, rh.gs(R.string.disk_full, Constants.MINIMUM_FREE_SPACE), this)
activeNames.addNotification(Notification.DISK_FULL, rh.gs(R.string.disk_full, Constants.MINIMUM_FREE_SPACE), Notification.NORMAL)
}
return value

View file

@ -3,7 +3,7 @@ package info.nightscout.plugins.constraints.versionChecker
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
@ -40,7 +40,7 @@ class VersionCheckerPlugin @Inject constructor(
.showInList(false)
.pluginName(R.string.version_checker),
aapsLogger, rh, injector
), Constraints {
), PluginConstraints {
enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) {
RELEASE(30, 60, 90),
@ -64,16 +64,16 @@ class VersionCheckerPlugin @Inject constructor(
checkWarning()
versionCheckerUtils.triggerCheckVersion()
if (lastCheckOlderThan(gracePeriod.veryOld.daysToMillis()))
value.set(aapsLogger, false, rh.gs(R.string.very_old_version), this)
value.set(false, rh.gs(R.string.very_old_version), this)
val endDate = sp.getLong(rh.gs(info.nightscout.core.utils.R.string.key_app_expiration) + "_" + config.VERSION_NAME, 0)
if (endDate != 0L && dateUtil.now() > endDate)
value.set(aapsLogger, false, rh.gs(R.string.application_expired), this)
value.set(false, rh.gs(R.string.application_expired), this)
return value
}
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (lastCheckOlderThan(gracePeriod.old.daysToMillis()))
maxIob.set(aapsLogger, 0.0, rh.gs(R.string.old_version), this)
maxIob.set(0.0, rh.gs(R.string.old_version), this)
else
maxIob

View file

@ -2,16 +2,15 @@ package info.nightscout.plugins.constraints.bgQualityCheck
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
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.InMemoryGlucoseValue
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.constraints.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
@ -35,7 +34,13 @@ class BgQualityCheckPluginTest : TestBase() {
private lateinit var plugin: BgQualityCheckPlugin
private val injector = HasAndroidInjector { AndroidInjector { } }
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
private val now = 100000000L
//private val autosensDataStore = AutosensDataStoreObject()
@ -46,7 +51,7 @@ class BgQualityCheckPluginTest : TestBase() {
injector,
aapsLogger,
rh,
RxBus(aapsSchedulers, aapsLogger),
rxBus,
iobCobCalculator,
aapsSchedulers,
fabricPrivacy,
@ -75,10 +80,46 @@ class BgQualityCheckPluginTest : TestBase() {
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.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
superData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = T.mins(20).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
superData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = T.mins(15).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
superData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = T.mins(10).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
superData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = T.mins(5).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(superData)
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
@ -205,16 +246,106 @@ class BgQualityCheckPluginTest : TestBase() {
// Flat data Libre
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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(0).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(flatData)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatData[0]))
@ -224,16 +355,106 @@ class BgQualityCheckPluginTest : TestBase() {
// Flat data Libre
val flatDataDexcom: MutableList<GlucoseValue> = ArrayList()
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-5).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 101.0, timestamp = now + T.mins(-10).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-15).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-20).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-25).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 99.0, timestamp = now + T.mins(-30).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-35).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-40).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = now + T.mins(-45).msecs(), sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE, trendArrow = GlucoseValue.TrendArrow.FLAT))
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(0).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-5).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 101.0,
timestamp = now + T.mins(-10).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-15).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-20).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-25).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 99.0,
timestamp = now + T.mins(-30).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-35).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-40).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
flatDataDexcom.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(-45).msecs(),
sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(flatDataDexcom)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatDataDexcom[0]))
@ -243,19 +464,100 @@ class BgQualityCheckPluginTest : TestBase() {
// 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT))
incompleteData.add(
GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 100.0,
timestamp = now + T.mins(0).msecs(),
sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
`when`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(incompleteData)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(incompleteData[0]))
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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER, 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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
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.LIBRE_1_OTHER,
trendArrow = GlucoseValue.TrendArrow.FLAT
)
)
plugin.processBgData() // must be at least 45 min old
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state)
}
@ -263,13 +565,13 @@ class BgQualityCheckPluginTest : TestBase() {
@Test
fun applyMaxIOBConstraintsTest() {
plugin.state = BgQualityCheck.State.UNKNOWN
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(ConstraintObject(10.0, injector)).value(), 0.001)
plugin.state = BgQualityCheck.State.FIVE_MIN_DATA
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(ConstraintObject(10.0, injector)).value(), 0.001)
plugin.state = BgQualityCheck.State.RECALCULATED
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
Assertions.assertEquals(10.0, plugin.applyMaxIOBConstraints(ConstraintObject(10.0, injector)).value(), 0.001)
plugin.state = BgQualityCheck.State.DOUBLED
Assertions.assertEquals(0.0, plugin.applyMaxIOBConstraints(Constraint(10.0)).value(), 0.001)
Assertions.assertEquals(0.0, plugin.applyMaxIOBConstraints(ConstraintObject(10.0, injector)).value(), 0.001)
}
}

View file

@ -2,8 +2,8 @@ package info.nightscout.plugins.constraints.objectives
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.constraints.R
@ -35,6 +35,9 @@ class ObjectivesPluginTest : TestBase() {
it.rh = rh
it.dateUtil = dateUtil
}
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@ -49,34 +52,30 @@ class ObjectivesPluginTest : TestBase() {
@Test fun notStartedObjectivesShouldLimitLoopInvocation() {
objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = 0
var c = Constraint(true)
c = objectivesPlugin.isLoopInvocationAllowed(c)
Assertions.assertEquals("Objectives: Objective 1 not started", c.getReasons(aapsLogger))
val c = objectivesPlugin.isLoopInvocationAllowed(ConstraintObject(true, injector))
Assertions.assertEquals("Objectives: Objective 1 not started", c.getReasons())
Assertions.assertEquals(false, c.value())
objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = dateUtil.now()
}
@Test fun notStartedObjective6ShouldLimitClosedLoop() {
objectivesPlugin.objectives[Objectives.MAXIOB_ZERO_CL_OBJECTIVE].startedOn = 0
var c = Constraint(true)
c = objectivesPlugin.isClosedLoopAllowed(c)
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 6 not started"))
val c = objectivesPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
Assertions.assertEquals(true, c.getReasons().contains("Objective 6 not started"))
Assertions.assertEquals(false, c.value())
}
@Test fun notStartedObjective8ShouldLimitAutosensMode() {
objectivesPlugin.objectives[Objectives.AUTOSENS_OBJECTIVE].startedOn = 0
var c = Constraint(true)
c = objectivesPlugin.isAutosensModeEnabled(c)
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 8 not started"))
val c = objectivesPlugin.isAutosensModeEnabled(ConstraintObject(true, injector))
Assertions.assertEquals(true, c.getReasons().contains("Objective 8 not started"))
Assertions.assertEquals(false, c.value())
}
@Test fun notStartedObjective10ShouldLimitSMBMode() {
objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0
var c = Constraint(true)
c = objectivesPlugin.isSMBModeEnabled(c)
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 9 not started"))
val c = objectivesPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
Assertions.assertEquals(true, c.getReasons().contains("Objective 9 not started"))
Assertions.assertEquals(false, c.value())
}
}

View file

@ -2,7 +2,7 @@ package info.nightscout.plugins.constraints.storage
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.interfaces.ResourceHelper
@ -20,6 +20,13 @@ class StorageConstraintPluginTest : TestBase() {
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var uiInteraction: UiInteraction
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
private lateinit var storageConstraintPlugin: StorageConstraintPlugin
@BeforeEach fun prepareMock() {
@ -42,9 +49,9 @@ class StorageConstraintPluginTest : TestBase() {
val mocked = MockedStorageConstraintPlugin({ AndroidInjector { } }, aapsLogger, rh, uiInteraction)
// Set free space under 200(Mb) to disable loop
mocked.memSize = 150L
Assertions.assertEquals(false, mocked.isClosedLoopAllowed(Constraint(true)).value())
Assertions.assertEquals(false, mocked.isClosedLoopAllowed(ConstraintObject(true, injector)).value())
// Set free space over 200(Mb) to enable loop
mocked.memSize = 300L
Assertions.assertEquals(true, mocked.isClosedLoopAllowed(Constraint(true)).value())
Assertions.assertEquals(true, mocked.isClosedLoopAllowed(ConstraintObject(true, injector)).value())
}
}

View file

@ -7,7 +7,6 @@ import info.nightscout.interfaces.insulin.Insulin
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.ui.UiInteraction
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.sharedtests.TestBase
@ -29,7 +28,6 @@ class InsulinOrefFreePeakPluginTest : TestBase() {
@Mock lateinit var sp: SP
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var rxBus: RxBus
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var config: Config
@Mock lateinit var hardLimits: HardLimits

View file

@ -27,6 +27,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.directionToIcon
import info.nightscout.core.graph.OverviewData
import info.nightscout.core.iob.displayText
@ -49,8 +50,7 @@ import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.aps.VariableSensitivityResult
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.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger
@ -121,7 +121,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var profileUtil: ProfileUtil
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var processedDeviceStatusData: ProcessedDeviceStatusData
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
@ -516,7 +516,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg)
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(ConstraintObject(quickWizardEntry.carbs(), injector)).value()
activity?.let {
if (abs(wizard.insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(wizard.insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) {
OKDialog.show(it, rh.gs(info.nightscout.core.ui.R.string.treatmentdeliveryerror), rh.gs(R.string.constraints_violation) + "\n" + rh.gs(R.string.change_your_input))

View file

@ -11,6 +11,7 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.iob.generateCOBString
import info.nightscout.core.iob.round
@ -34,8 +35,7 @@ import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit
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.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger
@ -91,7 +91,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private val smsManager: SmsManager?,
private val aapsSchedulers: AapsSchedulers,
private val sp: SP,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val rxBus: RxBus,
private val profileFunction: ProfileFunction,
private val profileUtil: ProfileUtil,
@ -732,7 +732,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else if (tempBasalPct == 0 && divided[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.sms_wrong_tbr_duration, durationStep)))
else {
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
tempBasalPct = constraintChecker.applyBasalPercentConstraints(ConstraintObject(tempBasalPct, injector), profile).value()
val passCode = generatePassCode()
val reply = rh.gs(R.string.smscommunicator_basal_pct_reply_with_code, tempBasalPct, duration, passCode)
receivedSms.processed = true
@ -787,7 +787,7 @@ class SmsCommunicatorPlugin @Inject constructor(
else if (tempBasal == 0.0 && divided[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.sms_wrong_tbr_duration, durationStep)))
else {
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value()
tempBasal = constraintChecker.applyBasalConstraints(ConstraintObject(tempBasal, injector), profile).value()
val passCode = generatePassCode()
val reply = rh.gs(R.string.smscommunicator_basal_reply_with_code, tempBasal, duration, passCode)
receivedSms.processed = true
@ -864,7 +864,7 @@ class SmsCommunicatorPlugin @Inject constructor(
} else {
var extended = SafeParse.stringToDouble(divided[1])
val duration = SafeParse.stringToInt(divided[2])
extended = constraintChecker.applyExtendedBolusConstraints(Constraint(extended)).value()
extended = constraintChecker.applyExtendedBolusConstraints(ConstraintObject(extended, injector)).value()
if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else {
val passCode = generatePassCode()
@ -918,7 +918,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processBOLUS(divided: Array<String>, receivedSms: Sms) {
var bolus = SafeParse.stringToDouble(divided[1])
val isMeal = divided.size > 2 && divided[2].equals("MEAL", ignoreCase = true)
bolus = constraintChecker.applyBolusConstraints(Constraint(bolus)).value()
bolus = constraintChecker.applyBolusConstraints(ConstraintObject(bolus, injector)).value()
if (divided.size == 3 && !isMeal) {
sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
} else if (bolus > 0.0) {
@ -1031,7 +1031,7 @@ class SmsCommunicatorPlugin @Inject constructor(
return
}
}
grams = constraintChecker.applyCarbsConstraints(Constraint(grams)).value()
grams = constraintChecker.applyCarbsConstraints(ConstraintObject(grams, injector)).value()
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else {
val passCode = generatePassCode()

View file

@ -3,6 +3,7 @@ package info.nightscout.plugins.general.wear.wearintegration
import android.app.NotificationManager
import android.content.Context
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.convertedToAbsolute
import info.nightscout.core.extensions.toStringShort
import info.nightscout.core.extensions.valueToUnits
@ -33,8 +34,7 @@ import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
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.constraints.ConstraintsChecker
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.InMemoryGlucoseValue
@ -104,7 +104,7 @@ class DataHandlerMobile @Inject constructor(
private val defaultValueHelper: DefaultValueHelper,
private val trendCalculator: TrendCalculator,
private val dateUtil: DateUtil,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val uel: UserEntryLogger,
private val activePlugin: ActivePlugin,
private val commandQueue: CommandQueue,
@ -269,7 +269,7 @@ class DataHandlerMobile @Inject constructor(
.observeOn(aapsSchedulers.io)
.subscribe({
aapsLogger.debug(LTag.WEAR, "ActionFillConfirmed received $it from ${it.sourceNodeId}")
if (constraintChecker.applyBolusConstraints(Constraint(it.insulin)).value() - it.insulin != 0.0) {
if (constraintChecker.applyBolusConstraints(ConstraintObject(it.insulin, injector)).value() - it.insulin != 0.0) {
ToastUtils.showToastInUiThread(context, "aborting: previously applied constraint changed")
sendError("aborting: previously applied constraint changed")
} else
@ -383,7 +383,7 @@ class DataHandlerMobile @Inject constructor(
return
}
val carbsBeforeConstraints = command.carbs
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(ConstraintObject(carbsBeforeConstraints, injector)).value()
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_carbs_constraint))
return
@ -480,7 +480,7 @@ class DataHandlerMobile @Inject constructor(
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg)
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(ConstraintObject(quickWizardEntry.carbs(), injector)).value()
if (carbsAfterConstraints != quickWizardEntry.carbs()) {
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_carbs_constraint))
return
@ -506,8 +506,8 @@ class DataHandlerMobile @Inject constructor(
}
private fun handleBolusPreCheck(command: EventData.ActionBolusPreCheck) {
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(command.insulin)).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(command.carbs)).value()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(ConstraintObject(command.insulin, injector)).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(ConstraintObject(command.carbs, injector)).value()
val pump = activePlugin.activePump
if (insulinAfterConstraints > 0 && (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected)) {
sendError(rh.gs(info.nightscout.core.ui.R.string.wizard_pump_not_available))
@ -530,7 +530,7 @@ class DataHandlerMobile @Inject constructor(
private fun handleECarbsPreCheck(command: EventData.ActionECarbsPreCheck) {
val startTimeStamp = System.currentTimeMillis() + T.mins(command.carbsTimeShift.toLong()).msecs()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(command.carbs)).value()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(ConstraintObject(command.carbs, injector)).value()
var message = rh.gs(info.nightscout.core.ui.R.string.carbs) + ": " + carbsAfterConstraints + rh.gs(R.string.grams_short) +
"\n" + rh.gs(info.nightscout.core.ui.R.string.time) + ": " + dateUtil.timeString(startTimeStamp) +
"\n" + rh.gs(info.nightscout.core.ui.R.string.duration) + ": " + command.duration + rh.gs(R.string.hour_short)
@ -558,7 +558,7 @@ class DataHandlerMobile @Inject constructor(
3 -> sp.getDouble("fill_button3", 0.0)
else -> return
}
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(ConstraintObject(amount, injector)).value()
var message = rh.gs(info.nightscout.core.ui.R.string.prime_fill) + ": " + insulinAfterConstraints + rh.gs(R.string.units_short)
if (insulinAfterConstraints - amount != 0.0) message += "\n" + rh.gs(info.nightscout.core.ui.R.string.constraint_applied)
rxBus.send(
@ -572,7 +572,7 @@ class DataHandlerMobile @Inject constructor(
}
private fun handleFillPreCheck(command: EventData.ActionFillPreCheck) {
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(command.insulin)).value()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(ConstraintObject(command.insulin, injector)).value()
var message = rh.gs(info.nightscout.core.ui.R.string.prime_fill) + ": " + insulinAfterConstraints + rh.gs(R.string.units_short)
if (insulinAfterConstraints - command.insulin != 0.0) message += "\n" + rh.gs(info.nightscout.core.ui.R.string.constraint_applied)
rxBus.send(

View file

@ -4,6 +4,7 @@ import android.telephony.SmsManager
import com.google.common.truth.Truth.assertThat
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CancelCurrentOfflineEventIfAnyTransaction
@ -16,8 +17,7 @@ import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.CobInfo
import info.nightscout.interfaces.iob.InMemoryGlucoseValue
import info.nightscout.interfaces.iob.IobTotal
@ -48,7 +48,7 @@ import org.mockito.invocation.InvocationOnMock
@Suppress("SpellCheckingInspection")
class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var loop: Loop
@Mock lateinit var profileSource: ProfileSource
@ -62,6 +62,9 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
private var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is PumpEnactResult) {
it.context = context
}
@ -836,7 +839,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 20% 20")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("TBR duration must be a multiple of 30 minutes and greater than 0.")
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(Constraint(20))
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(ConstraintObject(20, injector))
//BASAL 20% 30
smsCommunicatorPlugin.messages = ArrayList()
@ -862,7 +865,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 1 0")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("TBR duration must be a multiple of 30 minutes and greater than 0.")
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(ConstraintObject(1.0, injector))
//BASAL 1 20
smsCommunicatorPlugin.messages = ArrayList()
@ -870,7 +873,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 1 20")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("TBR duration must be a multiple of 30 minutes and greater than 0.")
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(ConstraintObject(1.0, injector))
//BASAL 1 30
smsCommunicatorPlugin.messages = ArrayList()
@ -918,7 +921,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("EXTENDED a%")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format")
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(ConstraintObject(1.0, injector))
//EXTENDED 1 0
smsCommunicatorPlugin.messages = ArrayList()
@ -955,7 +958,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format")
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(1.0, injector))
`when`(dateUtilMocked.now()).thenReturn(1000L)
`when`(sp.getLong(R.string.key_smscommunicator_remote_bolus_min_distance, T.msecs(Constants.remoteBolusMinDistance).mins())).thenReturn(15L)
//BOLUS 1
@ -964,7 +967,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS 1")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Remote bolus not available. Try again later.")
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
`when`(dateUtilMocked.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L)
//BOLUS 0
@ -980,8 +983,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS a")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format")
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(ConstraintObject(1.0, injector))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(1.0, injector))
//BOLUS 1
smsCommunicatorPlugin.messages = ArrayList()
@ -1078,7 +1081,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format")
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(0))
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(ConstraintObject(0, injector))
//CARBS 0
smsCommunicatorPlugin.messages = ArrayList()
@ -1086,7 +1089,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS 0")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format")
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(Constraint(1))
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(ConstraintObject(1, injector))
//CARBS 1
smsCommunicatorPlugin.messages = ArrayList()

View file

@ -12,6 +12,7 @@ import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataStoreObject
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.shared.utils.T
import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions
@ -46,7 +47,7 @@ class AutosensDataStoreTest : TestBase() {
@BeforeEach
fun mock() {
dateUtil = DateUtil(context)
dateUtil = DateUtilImpl(context)
}
@Test

View file

@ -12,7 +12,7 @@ import info.nightscout.interfaces.aps.AutosensResult
import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.interfaces.aps.Sensitivity.SensitivityType
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction
@ -51,7 +51,7 @@ class SensitivityOref1Plugin @Inject constructor(
.description(R.string.description_sensitivity_oref1)
.setDefault(),
injector, aapsLogger, rh, sp
), Constraints {
), PluginConstraints {
override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult {
val profile = profileFunction.getProfile()
@ -260,7 +260,7 @@ class SensitivityOref1Plugin @Inject constructor(
get() = SensitivityType.SENSITIVITY_OREF1
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
if (!isEnabled()) value.set(aapsLogger, false, rh.gs(R.string.uam_disabled_oref1_not_selected), this)
if (!isEnabled()) value.set(false, rh.gs(R.string.uam_disabled_oref1_not_selected), this)
return value
}
}

View file

@ -3,7 +3,6 @@ package info.nightscout.plugins.sync.nsclient
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.plugins.sync.R
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventChargingState
import info.nightscout.rx.events.EventNetworkChange
import info.nightscout.shared.interfaces.ResourceHelper
@ -20,7 +19,6 @@ class ReceiverDelegateTest : TestBase() {
@Mock lateinit var sp: SP
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var fabricPrivacy: FabricPrivacy
private val rxBus = RxBus(aapsSchedulers, aapsLogger)
@Mock private lateinit var receiverStatusStore: ReceiverStatusStore
private lateinit var sut: ReceiverDelegate

View file

@ -10,7 +10,6 @@ import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.sync.NsClient
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBase
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@ -30,7 +29,6 @@ internal class DataSyncWorkerTest : TestBase() {
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
@Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var nsClient: NsClient
@Mock lateinit var rxBus: RxBus
@Mock lateinit var nsClientV3Plugin: NSClientV3Plugin
@Mock lateinit var context: ContextWithInjector

View file

@ -26,7 +26,6 @@ import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
import info.nightscout.rx.bus.RxBus
import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.remotemodel.LastModified
import info.nightscout.shared.interfaces.ResourceHelper
@ -66,7 +65,6 @@ internal class LoadBgWorkerTest : TestBase() {
@Mock lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Mock lateinit var context: ContextWithInjector
private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger)
private lateinit var nsClientV3Plugin: NSClientV3Plugin
private lateinit var receiverDelegate: ReceiverDelegate
private lateinit var dataWorkerStorage: DataWorkerStorage

View file

@ -22,7 +22,7 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.core.utils.fabric.InstanceId;
import info.nightscout.interfaces.constraints.Constraint;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.PluginConstraints;
import info.nightscout.interfaces.notifications.Notification;
import info.nightscout.interfaces.plugin.PluginDescription;
import info.nightscout.interfaces.plugin.PluginType;
@ -86,23 +86,41 @@ import info.nightscout.shared.utils.T;
* Created by mike on 05.08.2016.
*/
@Singleton
public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
public class ComboPlugin extends PumpPluginBase implements Pump, PluginConstraints {
private final static PumpDescription pumpDescription = new PumpDescription();
@NonNull
private static final ComboPump pump = new ComboPump();
// collaborators
private final ProfileFunction profileFunction;
private final SP sp;
private RxBus rxBus;
private final CommandQueue commandQueue;
private final PumpSync pumpSync;
private final DateUtil dateUtil;
private final RuffyCommands ruffyScripter;
private final UiInteraction uiInteraction;
private final static PumpDescription pumpDescription = new PumpDescription();
@NonNull
private static final ComboPump pump = new ComboPump();
private RxBus rxBus;
private final BolusProgressReporter bolusProgressReporter = (state, percent, delivered) -> {
EventOverviewBolusProgress event = EventOverviewBolusProgress.INSTANCE;
switch (state) {
case PROGRAMMING:
event.setStatus(getRh().gs(R.string.combo_programming_bolus));
break;
case DELIVERING:
event.setStatus(getRh().gs(info.nightscout.core.ui.R.string.bolus_delivering, delivered));
break;
case DELIVERED:
event.setStatus(getRh().gs(info.nightscout.core.ui.R.string.bolus_delivered_successfully, delivered));
break;
case STOPPING:
event.setStatus(getRh().gs(R.string.bolusstopping));
break;
case STOPPED:
event.setStatus(getRh().gs(R.string.bolusstopped));
break;
}
event.setPercent(percent);
rxBus.send(event);
};
/**
* This is used to determine when to pass a bolus cancel request to the scripter
*/
@ -112,7 +130,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
* will reset this flag.
*/
private volatile boolean cancelBolus;
/**
* This is set (in {@link #checkHistory()} whenever a connection to the pump is made and
* indicates if new history records on the pump have been found. This effectively blocks
@ -128,7 +145,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
* direction - so that adding more complexity yields little benefit.
*/
private volatile boolean pumpHistoryChanged = false;
/**
* Cache of the last <=2 boluses on the pump. Used to detect changes in pump history,
* requiring reading more pump history. This is read/set in {@link #checkHistory()} when changed
@ -136,8 +152,11 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
* after bolus delivery. Newest record is the first one.
*/
private volatile List<Bolus> recentBoluses = new ArrayList<>(0);
private PumpEnactResult OPERATION_NOT_SUPPORTED;
// Constraints interface
private long lowSuspendOnlyLoopEnforcedUntil = 0;
private long violationWarningRaisedForBolusAt = 0;
private boolean validBasalRateProfileSelectedOnPump = true;
@Inject
public ComboPlugin(
@ -469,29 +488,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
}
}
private final BolusProgressReporter bolusProgressReporter = (state, percent, delivered) -> {
EventOverviewBolusProgress event = EventOverviewBolusProgress.INSTANCE;
switch (state) {
case PROGRAMMING:
event.setStatus(getRh().gs(R.string.combo_programming_bolus));
break;
case DELIVERING:
event.setStatus(getRh().gs(info.nightscout.core.ui.R.string.bolus_delivering, delivered));
break;
case DELIVERED:
event.setStatus(getRh().gs(info.nightscout.core.ui.R.string.bolus_delivered_successfully, delivered));
break;
case STOPPING:
event.setStatus(getRh().gs(R.string.bolusstopping));
break;
case STOPPED:
event.setStatus(getRh().gs(R.string.bolusstopped));
break;
}
event.setPercent(percent);
rxBus.send(event);
};
/**
* Updates Treatment records with carbs and boluses and delivers a bolus if needed
*/
@ -850,10 +846,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
return 0;
}
private interface CommandExecution {
CommandResult execute();
}
/**
* Runs a command, sets an activity if provided, retries if requested and updates fields
* concerned with last connection.
@ -980,7 +972,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
return null;
}
private void checkBasalRate(PumpState state) {
if (!pump.initialized) {
// no cached profile to compare against
@ -1386,22 +1377,17 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
return result;
}
// Constraints interface
private long lowSuspendOnlyLoopEnforcedUntil = 0;
private long violationWarningRaisedForBolusAt = 0;
private boolean validBasalRateProfileSelectedOnPump = true;
@NonNull @Override
public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) {
if (!validBasalRateProfileSelectedOnPump)
value.set(getAapsLogger(), false, getRh().gs(info.nightscout.core.ui.R.string.no_valid_basal_rate), this);
value.set(false, getRh().gs(info.nightscout.core.ui.R.string.no_valid_basal_rate), this);
return value;
}
@NonNull @Override
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis())
maxIob.setIfSmaller(getAapsLogger(), 0d, getRh().gs(info.nightscout.core.ui.R.string.limiting_iob, 0d, getRh().gs(R.string.unsafeusage)), this);
maxIob.setIfSmaller(0d, getRh().gs(info.nightscout.core.ui.R.string.limiting_iob, 0d, getRh().gs(R.string.unsafeusage)), this);
return maxIob;
}
@ -1409,4 +1395,8 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
public boolean canHandleDST() {
return false;
}
private interface CommandExecution {
CommandResult execute();
}
}

View file

@ -3,7 +3,7 @@ package info.nightscout.pump.combo
import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.PumpEnactResult
@ -12,7 +12,6 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.combo.ruffyscripter.RuffyScripter
import info.nightscout.pump.combo.ruffyscripter.history.Bolus
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
@ -37,6 +36,9 @@ class ComboPluginTest : TestBase() {
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is PumpEnactResult) {
it.context = context
}
@ -49,16 +51,15 @@ class ComboPluginTest : TestBase() {
fun prepareMocks() {
`when`(rh.gs(info.nightscout.core.ui.R.string.no_valid_basal_rate)).thenReturn("No valid basal rate read from pump")
`when`(context.getString(R.string.combo_pump_unsupported_operation)).thenReturn("Requested operation not supported by pump")
comboPlugin = ComboPlugin(injector, aapsLogger, RxBus(aapsSchedulers, aapsLogger), rh, profileFunction, sp, commandQueue, pumpSync, dateUtil, ruffyScripter, uiInteraction)
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, rh, profileFunction, sp, commandQueue, pumpSync, dateUtil, ruffyScripter, uiInteraction)
}
@Test
fun invalidBasalRateOnComboPumpShouldLimitLoopInvocation() {
comboPlugin.setPluginEnabled(PluginType.PUMP, true)
comboPlugin.setValidBasalRateProfileSelectedOnPump(false)
var c = Constraint(true)
c = comboPlugin.isLoopInvocationAllowed(c)
Assertions.assertEquals("Combo: No valid basal rate read from pump", c.getReasons(aapsLogger))
val c = comboPlugin.isLoopInvocationAllowed(ConstraintObject(true, injector))
Assertions.assertEquals("Combo: No valid basal rate read from pump", c.getReasons())
Assertions.assertEquals(false, c.value())
comboPlugin.setPluginEnabled(PluginType.PUMP, false)
}

View file

@ -13,6 +13,7 @@ apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
dependencies {
implementation project(':core:libraries')
implementation project(':core:interfaces')
implementation project(':core:main')
implementation project(':core:ui')
implementation project(':core:utils')
implementation(project(":pump:combov2:comboctl"))

View file

@ -25,12 +25,14 @@ import info.nightscout.comboctl.parser.AlertScreenContent
import info.nightscout.comboctl.parser.AlertScreenException
import info.nightscout.comboctl.parser.BatteryState
import info.nightscout.comboctl.parser.ReservoirState
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType
@ -101,14 +103,14 @@ import info.nightscout.comboctl.main.PumpManager as ComboCtlPumpManager
internal const val PUMP_ERROR_TIMEOUT_INTERVAL_MSECS = 1000L * 60 * 5
@Singleton
class ComboV2Plugin @Inject constructor (
class ComboV2Plugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
rh: ResourceHelper,
commandQueue: CommandQueue,
private val context: Context,
private val rxBus: RxBus,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val sp: SP,
private val pumpSync: PumpSync,
private val dateUtil: DateUtil,
@ -132,7 +134,7 @@ class ComboV2Plugin @Inject constructor (
commandQueue
),
Pump,
Constraints {
PluginConstraints {
// Coroutine scope and the associated job. All coroutines
// that are started in this plugin are part of this scope.
@ -208,6 +210,7 @@ class ComboV2Plugin @Inject constructor (
// overwritten. This check is performed in checkBasalProfile().
// In setNewBasalProfile(), this value is changed.
private var activeBasalProfile: BasalProfile? = null
// This is used for checking that the correct basal profile is
// active in the Combo. If not, loop invocation is disallowed.
// This is _not_ reset by disconnect(). That's on purpose; it
@ -220,22 +223,28 @@ class ComboV2Plugin @Inject constructor (
/*** Public functions and base class & interface overrides ***/
sealed class DriverState(@Suppress("unused") val label: String) {
// Initial state when the driver is created.
object NotInitialized : DriverState("notInitialized")
data object NotInitialized : DriverState("notInitialized")
// Driver is disconnected from the pump, or no pump
// is currently paired. In onStart() the driver state
// changes from NotInitialized to this.
object Disconnected : DriverState("disconnected")
data object Disconnected : DriverState("disconnected")
// Driver is currently connecting to the pump. isBusy()
// will return true in this state.
object Connecting : DriverState("connecting")
data object Connecting : DriverState("connecting")
// Driver is running checks on the pump, like verifying
// that the basal rate is OK, checking for any bolus
// and TBR activity that AAPS doesn't know about etc.
// isBusy() will return true in this state.
object CheckingPump : DriverState("checkingPump")
data object CheckingPump : DriverState("checkingPump")
// Driver is connected and ready to execute commands.
object Ready : DriverState("ready")
data object Ready : DriverState("ready")
// Driver is connected, but pump is suspended and
// cannot currently execute commands. This state is
// special in that it technically persists even after
@ -252,11 +261,12 @@ class ComboV2Plugin @Inject constructor (
// the pump is currently suspended or not. Use
// isSuspended() instead. See the pumpIsSuspended
// documentation for details.
object Suspended : DriverState("suspended")
data object Suspended : DriverState("suspended")
// Driver is currently executing a command.
// isBusy() will return true in this state.
class ExecutingCommand(val description: ComboCtlPump.CommandDescription) : DriverState("executingCommand")
object Error : DriverState("error")
data object Error : DriverState("error")
}
private val driverStateFlow = _driverStateFlow.asStateFlow()
@ -264,7 +274,9 @@ class ComboV2Plugin @Inject constructor (
// Used by ComboV2PairingActivity to launch its own
// custom activities that have a result.
var customDiscoveryActivityStartCallback: ((intent: Intent) -> Unit)?
set(value) { bluetoothInterface?.customDiscoveryActivityStartCallback = value }
set(value) {
bluetoothInterface?.customDiscoveryActivityStartCallback = value
}
get() = bluetoothInterface?.customDiscoveryActivityStartCallback
init {
@ -494,6 +506,7 @@ class ComboV2Plugin @Inject constructor (
// returning true then causes problems with AAPS' KeepAlive mechanism.
DriverState.CheckingPump,
is DriverState.ExecutingCommand -> true
else -> false
}
@ -509,6 +522,7 @@ class ComboV2Plugin @Inject constructor (
DriverState.Ready,
DriverState.Suspended,
is DriverState.ExecutingCommand -> true
else -> false
}
@ -516,7 +530,8 @@ class ComboV2Plugin @Inject constructor (
when (driverStateFlow.value) {
DriverState.Connecting,
DriverState.CheckingPump -> true
else -> false
else -> false
}
// There is no corresponding indicator for this
@ -554,7 +569,8 @@ class ComboV2Plugin @Inject constructor (
)
return
}
else -> Unit
else -> Unit
}
if (!isPaired()) {
@ -575,6 +591,7 @@ class ComboV2Plugin @Inject constructor (
unpairDueToPumpDataError()
return
}
else -> address
}
@ -608,13 +625,13 @@ class ComboV2Plugin @Inject constructor (
// the rxBus too early, potentially causing a situation where the connect()
// call isn't fully done yet, but the queue gets that event and thinks that
// it can try to reconnect now.
ComboCtlPump.State.Disconnected -> return@onEach
ComboCtlPump.State.Connecting -> DriverState.Connecting
ComboCtlPump.State.CheckingPump -> DriverState.CheckingPump
ComboCtlPump.State.ReadyForCommands -> DriverState.Ready
ComboCtlPump.State.Disconnected -> return@onEach
ComboCtlPump.State.Connecting -> DriverState.Connecting
ComboCtlPump.State.CheckingPump -> DriverState.CheckingPump
ComboCtlPump.State.ReadyForCommands -> DriverState.Ready
is ComboCtlPump.State.ExecutingCommand -> DriverState.ExecutingCommand(pumpState.description)
ComboCtlPump.State.Suspended -> DriverState.Suspended
is ComboCtlPump.State.Error -> DriverState.Error
ComboCtlPump.State.Suspended -> DriverState.Suspended
is ComboCtlPump.State.Error -> DriverState.Error
}
setDriverState(driverState)
}
@ -686,7 +703,8 @@ class ComboV2Plugin @Inject constructor (
pumpIsSuspended = when (it.stateFlow.value) {
ComboCtlPump.State.Suspended,
is ComboCtlPump.State.Error -> true
else -> false
else -> false
}
aapsLogger.debug(LTag.PUMP, "Pump is suspended: $pumpIsSuspended")
@ -970,8 +988,8 @@ class ComboV2Plugin @Inject constructor (
pumpStatus?.batteryState?.let { newState ->
val newLevel = when (newState) {
BatteryState.NO_BATTERY -> 5
BatteryState.LOW_BATTERY -> 25
BatteryState.NO_BATTERY -> 5
BatteryState.LOW_BATTERY -> 25
BatteryState.FULL_BATTERY -> 100
}
@ -996,7 +1014,7 @@ class ComboV2Plugin @Inject constructor (
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
val oldInsulinAmount = detailedBolusInfo.insulin
detailedBolusInfo.insulin = constraintChecker
.applyBolusConstraints(Constraint(detailedBolusInfo.insulin))
.applyBolusConstraints(ConstraintObject(detailedBolusInfo.insulin, injector))
.value()
aapsLogger.debug(
LTag.PUMP,
@ -1015,8 +1033,8 @@ class ComboV2Plugin @Inject constructor (
val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus()
val bolusReason = when (detailedBolusInfo.bolusType) {
DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL
DetailedBolusInfo.BolusType.SMB -> ComboCtlPump.StandardBolusReason.SUPERBOLUS
DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL
DetailedBolusInfo.BolusType.SMB -> ComboCtlPump.StandardBolusReason.SUPERBOLUS
DetailedBolusInfo.BolusType.PRIMING -> ComboCtlPump.StandardBolusReason.PRIMING_INFUSION_SET
}
@ -1055,13 +1073,15 @@ class ComboV2Plugin @Inject constructor (
bolusingEvent.status = rh.gs(info.nightscout.core.ui.R.string.bolus_delivering, detailedBolusInfo.insulin)
rxBus.send(bolusingEvent)
}
BasicProgressStage.Finished -> {
BasicProgressStage.Finished -> {
val bolusingEvent = EventOverviewBolusProgress
bolusingEvent.percent = (progressReport.overallProgress * 100.0).toInt()
bolusingEvent.status = "Bolus finished, performing post-bolus checks"
rxBus.send(bolusingEvent)
}
else -> Unit
else -> Unit
}
}
}
@ -1190,10 +1210,11 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.debug(LTag.PUMP, "Calculated percentage of $percentage% out of absolute rate $absoluteRate; rounded to: $roundedPercentage%; limited to: $limitedPercentage%")
val cctlTbrType = when (tbrType) {
PumpSync.TemporaryBasalType.NORMAL -> ComboCtlTbr.Type.NORMAL
PumpSync.TemporaryBasalType.NORMAL -> ComboCtlTbr.Type.NORMAL
PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND -> ComboCtlTbr.Type.EMULATED_COMBO_STOP
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
aapsLogger.error(
LTag.PUMP,
"PUMP_SUSPEND TBR type produced by AAPS for the TBR initiation even though this is supposed to only be produced by pump drivers"
@ -1221,10 +1242,11 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.debug(LTag.PUMP, "Got percentage of $percent%; rounded to: $roundedPercentage%; limited to: $limitedPercentage%")
val cctlTbrType = when (tbrType) {
PumpSync.TemporaryBasalType.NORMAL -> ComboCtlTbr.Type.NORMAL
PumpSync.TemporaryBasalType.NORMAL -> ComboCtlTbr.Type.NORMAL
PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND -> ComboCtlTbr.Type.EMULATED_COMBO_STOP
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
aapsLogger.error(
LTag.PUMP,
"PUMP_SUSPEND TBR type produced by AAPS for the TBR initiation even though this is supposed to only be produced by pump drivers"
@ -1277,10 +1299,13 @@ class ComboV2Plugin @Inject constructor (
val tbrComment = when (acquiredPump.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) {
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)
}
@ -1381,7 +1406,7 @@ class ComboV2Plugin @Inject constructor (
} ?: aapsLogger.info(
LTag.PUMP,
"Cannot include reservoir level in JSON status " +
"since no such level is currently known"
"since no such level is currently known"
)
put("extended", JSONObject().apply {
put("Version", version)
@ -1401,15 +1426,17 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.info(
LTag.PUMP,
"Cannot include base basal rate in JSON status " +
"since no basal profile is currently active"
"since no basal profile is currently active"
)
put("ActiveProfile", profileName)
when (val alert = lastComboAlert) {
is AlertScreenContent.Warning ->
put("WarningCode", alert.code)
is AlertScreenContent.Error ->
is AlertScreenContent.Error ->
put("ErrorCode", alert.code)
else -> Unit
else -> Unit
}
})
}
@ -1448,8 +1475,8 @@ class ComboV2Plugin @Inject constructor (
val alertCodeString = when (val alert = lastComboAlert) {
is AlertScreenContent.Warning -> "W${alert.code}"
is AlertScreenContent.Error -> "E${alert.code}"
else -> null
is AlertScreenContent.Error -> "E${alert.code}"
else -> null
}
if (alertCodeString != null)
lines += rh.gs(R.string.combov2_short_status_alert, alertCodeString)
@ -1476,8 +1503,8 @@ class ComboV2Plugin @Inject constructor (
it.availableUnitsInReservoir
)
val batteryStateDesc = when (it.batteryState) {
BatteryState.NO_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_empty)
BatteryState.LOW_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_low)
BatteryState.NO_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_empty)
BatteryState.LOW_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_low)
BatteryState.FULL_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_full)
}
lines += rh.gs(
@ -1562,9 +1589,9 @@ class ComboV2Plugin @Inject constructor (
val reason = when (timeChangeType) {
TimeChangeType.TimezoneChanged -> rh.gs(R.string.combov2_timezone_changed)
TimeChangeType.TimeChanged -> rh.gs(R.string.combov2_datetime_changed)
TimeChangeType.DSTStarted -> rh.gs(R.string.combov2_dst_started)
TimeChangeType.DSTEnded -> rh.gs(R.string.combov2_dst_ended)
TimeChangeType.TimeChanged -> rh.gs(R.string.combov2_datetime_changed)
TimeChangeType.DSTStarted -> rh.gs(R.string.combov2_dst_started)
TimeChangeType.DSTEnded -> rh.gs(R.string.combov2_dst_ended)
}
// Updating pump status implicitly also updates the pump's local datetime,
// which is what we want after the system datetime/timezone/DST changed.
@ -1594,12 +1621,7 @@ class ComboV2Plugin @Inject constructor (
)
if (!isAllowed) {
value.set(
aapsLogger,
false,
rh.gs(R.string.combov2_incorrect_active_basal_profile, lastActiveBasalProfileNumber),
this
)
value.set(false, rh.gs(R.string.combov2_incorrect_active_basal_profile, lastActiveBasalProfileNumber), this)
}
} else {
aapsLogger.info(
@ -1753,7 +1775,6 @@ class ComboV2Plugin @Inject constructor (
// the PumpManager onPumpUnpaired callback.
}
/*** User interface flows ***/
// "UI flows" are hot flows that are meant to be used for showing
@ -1788,6 +1809,7 @@ class ComboV2Plugin @Inject constructor (
// establishing a BT connection, or delivering a bolus, setting
// a basal rate factor, reading the current pump datetime etc.
data class CurrentActivityInfo(val description: String, val overallProgress: Double)
private fun noCurrentActivity() = CurrentActivityInfo("", 0.0)
private var _currentActivityUIFlow = MutableStateFlow(noCurrentActivity())
val currentActivityUIFlow = _currentActivityUIFlow.asStateFlow()
@ -1799,6 +1821,7 @@ class ComboV2Plugin @Inject constructor (
val batteryStateUIFlow = _batteryStateUIFlow.asStateFlow()
data class ReservoirLevel(val state: ReservoirState, val availableUnits: Int)
private var _reservoirLevelUIFlow = MutableStateFlow<ReservoirLevel?>(null)
val reservoirLevelUIFlow = _reservoirLevelUIFlow.asStateFlow()
@ -1830,7 +1853,6 @@ class ComboV2Plugin @Inject constructor (
private var _displayFrameUIFlow = MutableSharedFlow<DisplayFrame?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val displayFrameUIFlow = _displayFrameUIFlow.asSharedFlow()
/*** Misc private functions ***/
private fun setupUiFlows(acquiredPump: ComboCtlPump) {
@ -1845,6 +1867,7 @@ class ComboV2Plugin @Inject constructor (
R.string.combov2_establishing_bt_connection,
progStage.currentAttemptNr
)
BasicProgressStage.PerformingConnectionHandshake -> rh.gs(R.string.combov2_pairing_performing_handshake)
else -> ""
}
@ -1860,10 +1883,12 @@ class ComboV2Plugin @Inject constructor (
val description = when (progressReport.stage) {
RTCommandProgressStage.SettingDateTimeHour,
RTCommandProgressStage.SettingDateTimeMinute -> rh.gs(R.string.combov2_setting_current_pump_time)
RTCommandProgressStage.SettingDateTimeYear,
RTCommandProgressStage.SettingDateTimeMonth,
RTCommandProgressStage.SettingDateTimeDay -> rh.gs(R.string.combov2_setting_current_pump_date)
else -> ""
RTCommandProgressStage.SettingDateTimeDay -> rh.gs(R.string.combov2_setting_current_pump_date)
else -> ""
}
_currentActivityUIFlow.value = CurrentActivityInfo(
description,
@ -1877,7 +1902,8 @@ class ComboV2Plugin @Inject constructor (
val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.GettingBasalProfile ->
rh.gs(R.string.combov2_getting_basal_profile, stage.numSetFactors)
else -> ""
else -> ""
}
_currentActivityUIFlow.value = CurrentActivityInfo(
description,
@ -1891,7 +1917,8 @@ class ComboV2Plugin @Inject constructor (
val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.SettingBasalProfile ->
rh.gs(R.string.combov2_setting_basal_profile, stage.numSetFactors)
else -> ""
else -> ""
}
_currentActivityUIFlow.value = CurrentActivityInfo(
description,
@ -1906,10 +1933,11 @@ class ComboV2Plugin @Inject constructor (
is RTCommandProgressStage.DeliveringBolus ->
rh.gs(
R.string.combov2_delivering_bolus,
stage.deliveredImmediateAmount .cctlBolusToIU(),
stage.deliveredImmediateAmount.cctlBolusToIU(),
stage.totalImmediateAmount.cctlBolusToIU()
)
else -> ""
else -> ""
}
_currentActivityUIFlow.value = CurrentActivityInfo(
description,
@ -1981,7 +2009,7 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.debug(LTag.PUMP, "Handling pump event $event")
when (event) {
is ComboCtlPump.Event.BatteryLow -> {
is ComboCtlPump.Event.BatteryLow -> {
uiInteraction.addNotification(
Notification.COMBO_PUMP_ALARM,
text = rh.gs(R.string.combov2_battery_low_warning),
@ -1989,7 +2017,7 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.ReservoirLow -> {
is ComboCtlPump.Event.ReservoirLow -> {
uiInteraction.addNotification(
Notification.COMBO_PUMP_ALARM,
text = rh.gs(R.string.combov2_reservoir_low_warning),
@ -1997,7 +2025,7 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.QuickBolusInfused -> {
is ComboCtlPump.Event.QuickBolusInfused -> {
pumpSync.syncBolusWithPumpId(
event.timestamp.toEpochMilliseconds(),
event.bolusAmount.cctlBolusToIU(),
@ -2010,8 +2038,8 @@ class ComboV2Plugin @Inject constructor (
is ComboCtlPump.Event.StandardBolusInfused -> {
val bolusType = when (event.standardBolusReason) {
ComboCtlPump.StandardBolusReason.NORMAL -> DetailedBolusInfo.BolusType.NORMAL
ComboCtlPump.StandardBolusReason.SUPERBOLUS -> DetailedBolusInfo.BolusType.SMB
ComboCtlPump.StandardBolusReason.NORMAL -> DetailedBolusInfo.BolusType.NORMAL
ComboCtlPump.StandardBolusReason.SUPERBOLUS -> DetailedBolusInfo.BolusType.SMB
ComboCtlPump.StandardBolusReason.PRIMING_INFUSION_SET -> DetailedBolusInfo.BolusType.PRIMING
}
pumpSync.syncBolusWithPumpId(
@ -2036,7 +2064,7 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.ExtendedBolusEnded -> {
is ComboCtlPump.Event.ExtendedBolusEnded -> {
pumpSync.syncStopExtendedBolusWithPumpId(
event.timestamp.toEpochMilliseconds(),
event.bolusId,
@ -2045,15 +2073,15 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.TbrStarted -> {
is ComboCtlPump.Event.TbrStarted -> {
aapsLogger.debug(LTag.PUMP, "Pump reports TBR started; expected state according to AAPS: ${pumpSync.expectedPumpState()}")
val tbrStartTimestampInMs = event.tbr.timestamp.toEpochMilliseconds()
val tbrType = when (event.tbr.type) {
ComboCtlTbr.Type.NORMAL -> PumpSync.TemporaryBasalType.NORMAL
ComboCtlTbr.Type.NORMAL -> PumpSync.TemporaryBasalType.NORMAL
ComboCtlTbr.Type.EMULATED_100_PERCENT -> PumpSync.TemporaryBasalType.NORMAL
ComboCtlTbr.Type.SUPERBOLUS -> PumpSync.TemporaryBasalType.SUPERBOLUS
ComboCtlTbr.Type.EMULATED_COMBO_STOP -> PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND
ComboCtlTbr.Type.COMBO_STOPPED -> PumpSync.TemporaryBasalType.PUMP_SUSPEND
ComboCtlTbr.Type.SUPERBOLUS -> PumpSync.TemporaryBasalType.SUPERBOLUS
ComboCtlTbr.Type.EMULATED_COMBO_STOP -> PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND
ComboCtlTbr.Type.COMBO_STOPPED -> PumpSync.TemporaryBasalType.PUMP_SUSPEND
}
pumpSync.syncTemporaryBasalWithPumpId(
timestamp = tbrStartTimestampInMs,
@ -2067,7 +2095,7 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.TbrEnded -> {
is ComboCtlPump.Event.TbrEnded -> {
aapsLogger.debug(LTag.PUMP, "Pump reports TBR ended; expected state according to AAPS: ${pumpSync.expectedPumpState()}")
val tbrEndTimestampInMs = event.timestampWhenTbrEnded.toEpochMilliseconds()
pumpSync.syncStopTemporaryBasalWithPumpId(
@ -2078,7 +2106,7 @@ class ComboV2Plugin @Inject constructor (
)
}
is ComboCtlPump.Event.UnknownTbrDetected -> {
is ComboCtlPump.Event.UnknownTbrDetected -> {
// Inform about this unknown TBR that was observed (and automatically aborted).
val remainingDurationString = String.format(
"%02d:%02d",
@ -2096,7 +2124,7 @@ class ComboV2Plugin @Inject constructor (
)
}
else -> Unit
else -> Unit
}
}
@ -2229,9 +2257,11 @@ class ComboV2Plugin @Inject constructor (
when (driverStateUIFlow.value) {
DriverState.Error,
DriverState.Suspended -> false
else -> true
else -> true
}
}
else -> true
}
if (updateUIState) {
@ -2264,10 +2294,12 @@ class ComboV2Plugin @Inject constructor (
if (oldState != DriverState.Suspended)
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
DriverState.Suspended -> {
if (oldState != DriverState.Ready)
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
}
else -> Unit
}
}
@ -2336,8 +2368,8 @@ class ComboV2Plugin @Inject constructor (
when (alert) {
is AlertScreenContent.Warning -> {
val desc = when (alert.code) {
4 -> rh.gs(R.string.combov2_warning_4)
10 -> rh.gs(R.string.combov2_warning_10)
4 -> rh.gs(R.string.combov2_warning_4)
10 -> rh.gs(R.string.combov2_warning_10)
else -> ""
}
@ -2345,18 +2377,18 @@ class ComboV2Plugin @Inject constructor (
if (desc.isEmpty()) "" else ": $desc"
}
is AlertScreenContent.Error -> {
is AlertScreenContent.Error -> {
val desc = when (alert.code) {
1 -> rh.gs(R.string.combov2_error_1)
2 -> rh.gs(R.string.combov2_error_2)
4 -> rh.gs(R.string.combov2_error_4)
5 -> rh.gs(R.string.combov2_error_5)
6 -> rh.gs(R.string.combov2_error_6)
7 -> rh.gs(R.string.combov2_error_7)
8 -> rh.gs(R.string.combov2_error_8)
9 -> rh.gs(R.string.combov2_error_9)
10 -> rh.gs(R.string.combov2_error_10)
11 -> rh.gs(R.string.combov2_error_11)
1 -> rh.gs(R.string.combov2_error_1)
2 -> rh.gs(R.string.combov2_error_2)
4 -> rh.gs(R.string.combov2_error_4)
5 -> rh.gs(R.string.combov2_error_5)
6 -> rh.gs(R.string.combov2_error_6)
7 -> rh.gs(R.string.combov2_error_7)
8 -> rh.gs(R.string.combov2_error_8)
9 -> rh.gs(R.string.combov2_error_9)
10 -> rh.gs(R.string.combov2_error_10)
11 -> rh.gs(R.string.combov2_error_11)
else -> ""
}
@ -2364,7 +2396,7 @@ class ComboV2Plugin @Inject constructor (
if (desc.isEmpty()) "" else ": $desc"
}
else -> rh.gs(R.string.combov2_unrecognized_alert)
else -> rh.gs(R.string.combov2_unrecognized_alert)
}
private fun notifyAboutComboAlert(alert: AlertScreenContent) {
@ -2411,6 +2443,7 @@ class ComboV2Plugin @Inject constructor (
when (driverStateFlow.value) {
DriverState.NotInitialized,
DriverState.Disconnected -> true
else -> false
else -> false
}
}

View file

@ -10,9 +10,9 @@ import info.nightscout.androidaps.danaRKorean.services.DanaRKoreanExecutionServi
import info.nightscout.androidaps.danar.AbstractDanaRPlugin
import info.nightscout.androidaps.danar.R
import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.pump.DetailedBolusInfo
@ -51,7 +51,7 @@ class DanaRKoreanPlugin @Inject constructor(
rxBus: RxBus,
private val context: Context,
rh: ResourceHelper,
constraintChecker: Constraints,
constraintChecker: ConstraintsChecker,
activePlugin: ActivePlugin,
sp: SP,
commandQueue: CommandQueue,
@ -147,7 +147,7 @@ class DanaRKoreanPlugin @Inject constructor(
}
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(ConstraintObject(detailedBolusInfo.insulin, injector)).value()
require(detailedBolusInfo.carbs > 0)
return if (detailedBolusInfo.insulin > 0) {
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id)
@ -192,7 +192,7 @@ class DanaRKoreanPlugin @Inject constructor(
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
// Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this
val absoluteRateAfterConstraint = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
val absoluteRateAfterConstraint = constraintChecker.applyBasalConstraints(ConstraintObject(absoluteRate, injector), profile).value()
var doTempOff = baseBasalRate - absoluteRateAfterConstraint == 0.0 && absoluteRateAfterConstraint >= 0.10
val doLowTemp = absoluteRateAfterConstraint < baseBasalRate || absoluteRateAfterConstraint < 0.10
val doHighTemp = absoluteRateAfterConstraint > baseBasalRate && !useExtendedBoluses
@ -266,7 +266,7 @@ class DanaRKoreanPlugin @Inject constructor(
val durationInHalfHours = max(durationInMinutes / 30, 1)
// We keep current basal running so need to sub current basal
var extendedRateToSet: Double = absoluteRateAfterConstraint - baseBasalRate
extendedRateToSet = constraintChecker.applyBasalConstraints(Constraint(extendedRateToSet), profile).value()
extendedRateToSet = constraintChecker.applyBasalConstraints(ConstraintObject(extendedRateToSet, injector), profile).value()
// needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2) // *2 because of half hours

View file

@ -34,7 +34,7 @@ import info.nightscout.androidaps.danar.comm.MsgStatusBolusExtended;
import info.nightscout.androidaps.danar.comm.MsgStatusTempBasal;
import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService;
import info.nightscout.interfaces.Constants;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.notifications.Notification;
import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.profile.ProfileFunction;
@ -62,7 +62,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
@Inject AAPSLogger aapsLogger;
@Inject RxBus rxBus;
@Inject ResourceHelper rh;
@Inject Constraints constraintChecker;
@Inject ConstraintsChecker constraintChecker;
@Inject DanaPump danaPump;
@Inject DanaRPlugin danaRPlugin;
@Inject DanaRKoreanPlugin danaRKoreanPlugin;
@ -83,12 +83,6 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
mBinder = new LocalBinder();
}
public class LocalBinder extends Binder {
public DanaRKoreanExecutionService getServiceInstance() {
return DanaRKoreanExecutionService.this;
}
}
@SuppressLint("MissingPermission") public void connect() {
if (mConnectionInProgress)
return;
@ -330,4 +324,10 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
return null;
}
public class LocalBinder extends Binder {
public DanaRKoreanExecutionService getServiceInstance() {
return DanaRKoreanExecutionService.this;
}
}
}

View file

@ -16,9 +16,9 @@ import info.nightscout.androidaps.danaRv2.services.DanaRv2ExecutionService;
import info.nightscout.androidaps.danar.AbstractDanaRPlugin;
import info.nightscout.androidaps.danar.R;
import info.nightscout.annotations.OpenForTesting;
import info.nightscout.core.constraints.ConstraintObject;
import info.nightscout.core.utils.fabric.FabricPrivacy;
import info.nightscout.interfaces.constraints.Constraint;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.plugin.ActivePlugin;
import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.pump.DetailedBolusInfo;
@ -53,6 +53,19 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
private final DetailedBolusInfoStorage detailedBolusInfoStorage;
private final TemporaryBasalStorage temporaryBasalStorage;
private final FabricPrivacy fabricPrivacy;
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.PUMP, "Service is disconnected");
sExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
aapsLogger.debug(LTag.PUMP, "Service is connected");
DanaRv2ExecutionService.LocalBinder mLocalBinder = (DanaRv2ExecutionService.LocalBinder) service;
sExecutionService = mLocalBinder.getServiceInstance();
}
};
@Inject
public DanaRv2Plugin(
@ -62,7 +75,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
RxBus rxBus,
Context context,
ResourceHelper rh,
Constraints constraintChecker,
ConstraintsChecker constraintChecker,
ActivePlugin activePlugin,
SP sp,
CommandQueue commandQueue,
@ -111,20 +124,6 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
super.onStop();
}
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.PUMP, "Service is disconnected");
sExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
aapsLogger.debug(LTag.PUMP, "Service is connected");
DanaRv2ExecutionService.LocalBinder mLocalBinder = (DanaRv2ExecutionService.LocalBinder) service;
sExecutionService = mLocalBinder.getServiceInstance();
}
};
// Plugin base interface
@NonNull
@Override
@ -160,7 +159,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
// Pump interface
@NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value();
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(new ConstraintObject<>(detailedBolusInfo.insulin, getInjector())).value();
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
// v2 stores end time for bolus, we need to adjust time
// default delivery speed is 12 sec/U
@ -225,7 +224,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
PumpEnactResult result = new PumpEnactResult(getInjector());
absoluteRate = constraintChecker.applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
absoluteRate = constraintChecker.applyBasalConstraints(new ConstraintObject<>(absoluteRate, getInjector()), profile).value();
boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d && absoluteRate >= 0.10d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate() || absoluteRate < 0.10d;
@ -291,7 +290,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) {
DanaPump pump = danaPump;
PumpEnactResult result = new PumpEnactResult(getInjector());
percent = constraintChecker.applyBasalPercentConstraints(new Constraint<>(percent), profile).value();
percent = constraintChecker.applyBasalPercentConstraints(new ConstraintObject<>(percent, getInjector()), profile).value();
if (percent < 0) {
result.isTempCancel(false).enacted(false).success(false).comment(info.nightscout.core.ui.R.string.invalid_input);
aapsLogger.error("setTempBasalPercent: Invalid input");
@ -352,7 +351,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
@NonNull @Override
public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
DanaPump pump = danaPump;
insulin = constraintChecker.applyExtendedBolusConstraints(new Constraint<>(insulin)).value();
insulin = constraintChecker.applyExtendedBolusConstraints(new ConstraintObject<>(insulin, getInjector())).value();
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.INSTANCE.roundTo(insulin, getPumpDescription().getExtendedBolusStep());

View file

@ -7,8 +7,10 @@ import org.json.JSONObject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService;
import info.nightscout.core.constraints.ConstraintObject;
import info.nightscout.interfaces.constraints.Constraint;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.constraints.PluginConstraints;
import info.nightscout.interfaces.notifications.Notification;
import info.nightscout.interfaces.plugin.ActivePlugin;
import info.nightscout.interfaces.plugin.OwnDatabasePlugin;
@ -46,7 +48,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
* Created by mike on 28.01.2018.
*/
public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump, Dana, Constraints, OwnDatabasePlugin {
public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump, Dana, PluginConstraints, OwnDatabasePlugin {
protected AbstractDanaRExecutionService sExecutionService;
protected CompositeDisposable disposable = new CompositeDisposable();
@ -55,7 +57,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
protected PumpDescription pumpDescription = new PumpDescription();
protected DanaPump danaPump;
protected Constraints constraintChecker;
protected ConstraintsChecker constraintChecker;
protected RxBus rxBus;
protected ActivePlugin activePlugin;
protected SP sp;
@ -65,11 +67,12 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
protected UiInteraction uiInteraction;
protected DanaHistoryDatabase danaHistoryDatabase;
protected DecimalFormatter decimalFormatter;
protected AbstractDanaRPlugin(
HasAndroidInjector injector,
DanaPump danaPump,
ResourceHelper rh,
Constraints constraintChecker,
ConstraintsChecker constraintChecker,
AAPSLogger aapsLogger,
AapsSchedulers aapsSchedulers,
CommandQueue commandQueue,
@ -223,7 +226,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
@NonNull @Override
public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) {
PumpEnactResult result = new PumpEnactResult(getInjector());
percent = constraintChecker.applyBasalPercentConstraints(new Constraint<>(percent), profile).value();
percent = constraintChecker.applyBasalPercentConstraints(new ConstraintObject<>(percent, getInjector()), profile).value();
if (percent < 0) {
result.isTempCancel(false).enacted(false).success(false).comment(info.nightscout.core.ui.R.string.invalid_input);
getAapsLogger().error("setTempBasalPercent: Invalid input");
@ -270,7 +273,7 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
@NonNull @Override
public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
insulin = constraintChecker.applyExtendedBolusConstraints(new Constraint<>(insulin)).value();
insulin = constraintChecker.applyExtendedBolusConstraints(new ConstraintObject<>(insulin, getInjector())).value();
// needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.INSTANCE.roundTo(insulin, getPumpDescription().getExtendedBolusStep());
@ -462,21 +465,21 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
@NonNull @Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, @NonNull Profile profile) {
absoluteRate.setIfSmaller(getAapsLogger(), danaPump.getMaxBasal(), getRh().gs(info.nightscout.core.ui.R.string.limitingbasalratio, danaPump.getMaxBasal(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
absoluteRate.setIfSmaller(danaPump.getMaxBasal(), getRh().gs(info.nightscout.core.ui.R.string.limitingbasalratio, danaPump.getMaxBasal(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
return absoluteRate;
}
@NonNull @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, @NonNull Profile profile) {
percentRate.setIfGreater(getAapsLogger(), 0, getRh().gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, getRh().gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getAapsLogger(), getPumpDescription().getMaxTempPercent(), getRh().gs(info.nightscout.core.ui.R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
percentRate.setIfGreater(0, getRh().gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, getRh().gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().getMaxTempPercent(), getRh().gs(info.nightscout.core.ui.R.string.limitingpercentrate, getPumpDescription().getMaxTempPercent(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
return percentRate;
}
@NonNull @Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
insulin.setIfSmaller(getAapsLogger(), danaPump.getMaxBolus(), getRh().gs(info.nightscout.core.ui.R.string.limitingbolus, danaPump.getMaxBolus(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
insulin.setIfSmaller(danaPump.getMaxBolus(), getRh().gs(info.nightscout.core.ui.R.string.limitingbolus, danaPump.getMaxBolus(), getRh().gs(info.nightscout.core.ui.R.string.pumplimit)), this);
return insulin;
}

View file

@ -14,9 +14,9 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.danar.services.DanaRExecutionService;
import info.nightscout.annotations.OpenForTesting;
import info.nightscout.core.constraints.ConstraintObject;
import info.nightscout.core.utils.fabric.FabricPrivacy;
import info.nightscout.interfaces.constraints.Constraint;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.plugin.ActivePlugin;
import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.pump.DetailedBolusInfo;
@ -46,8 +46,20 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
private final AAPSLogger aapsLogger;
private final Context context;
private final ResourceHelper rh;
private final Constraints constraints;
private final FabricPrivacy fabricPrivacy;
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.PUMP, "Service is disconnected");
sExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
aapsLogger.debug(LTag.PUMP, "Service is connected");
DanaRExecutionService.LocalBinder mLocalBinder = (DanaRExecutionService.LocalBinder) service;
sExecutionService = mLocalBinder.getServiceInstance();
}
};
@Inject
public DanaRPlugin(
@ -57,7 +69,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
RxBus rxBus,
Context context,
ResourceHelper rh,
Constraints constraints,
ConstraintsChecker constraintsChecker,
ActivePlugin activePlugin,
SP sp,
CommandQueue commandQueue,
@ -69,11 +81,10 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
DanaHistoryDatabase danaHistoryDatabase,
DecimalFormatter decimalFormatter
) {
super(injector, danaPump, rh, constraints, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync, uiInteraction, danaHistoryDatabase, decimalFormatter);
super(injector, danaPump, rh, constraintsChecker, aapsLogger, aapsSchedulers, commandQueue, rxBus, activePlugin, sp, dateUtil, pumpSync, uiInteraction, danaHistoryDatabase, decimalFormatter);
this.aapsLogger = aapsLogger;
this.context = context;
this.rh = rh;
this.constraints = constraints;
this.fabricPrivacy = fabricPrivacy;
useExtendedBoluses = sp.getBoolean(info.nightscout.core.utils.R.string.key_danar_useextended, false);
@ -114,20 +125,6 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
super.onStop();
}
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
aapsLogger.debug(LTag.PUMP, "Service is disconnected");
sExecutionService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
aapsLogger.debug(LTag.PUMP, "Service is connected");
DanaRExecutionService.LocalBinder mLocalBinder = (DanaRExecutionService.LocalBinder) service;
sExecutionService = mLocalBinder.getServiceInstance();
}
};
// Plugin base interface
@NonNull
@Override
@ -163,7 +160,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
@NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
detailedBolusInfo.insulin = constraints.applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value();
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(new ConstraintObject<>(detailedBolusInfo.insulin, getInjector())).value();
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.getId());
boolean connectionOK = false;
@ -210,7 +207,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
//This should not be needed while using queue because connection should be done before calling this
PumpEnactResult result = new PumpEnactResult(getInjector());
absoluteRate = constraints.applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
absoluteRate = constraintChecker.applyBasalConstraints(new ConstraintObject<>(absoluteRate, getInjector()), profile).value();
boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d && absoluteRate >= 0.10d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate() || absoluteRate < 0.10d;
@ -289,7 +286,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
// We keep current basal running so need to sub current basal
double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = constraints.applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value();
extendedRateToSet = constraintChecker.applyBasalConstraints(new ConstraintObject<>(extendedRateToSet, getInjector()), profile).value();
// needs to be rounded to 0.1
extendedRateToSet = Round.INSTANCE.roundTo(extendedRateToSet, pumpDescription.getExtendedBolusStep() * 2); // *2 because of half hours

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danar.comm.MessageOriginalNames.getName
import info.nightscout.androidaps.utils.CRC.getCrc16
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.PumpSync
@ -48,7 +48,7 @@ open class MessageBase(injector: HasAndroidInjector) {
@Inject lateinit var commandQueue: CommandQueue
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var pumpSync: PumpSync
@Inject lateinit var danaHistoryRecordDao: DanaHistoryRecordDao
@Inject lateinit var uiInteraction: UiInteraction

View file

@ -1,10 +1,9 @@
package info.nightscout.androidaps.danar.comm
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.rx.logging.LTag
class MsgBolusStart(
injector: HasAndroidInjector,
private var amount: Double
@ -13,7 +12,7 @@ class MsgBolusStart(
init {
setCommand(0x0102)
// HARDCODED LIMIT
amount = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
amount = constraintChecker.applyBolusConstraints(ConstraintObject(amount, injector)).value()
addParamInt((amount * 100).toInt())
aapsLogger.debug(LTag.PUMPBTCOMM, "Bolus start : $amount")
}

View file

@ -1,10 +1,9 @@
package info.nightscout.androidaps.danar.comm
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.rx.logging.LTag
class MsgBolusStartWithSpeed(
injector: HasAndroidInjector,
private var amount: Double,
@ -14,7 +13,7 @@ class MsgBolusStartWithSpeed(
init {
setCommand(0x0104)
// HARDCODED LIMIT
amount = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
amount = constraintChecker.applyBolusConstraints(ConstraintObject(amount, injector)).value()
addParamInt((amount * 100).toInt())
addParamByte(speed.toByte())
aapsLogger.debug(LTag.PUMPBTCOMM, "Bolus start : $amount speed: $speed")
@ -24,10 +23,10 @@ class MsgBolusStartWithSpeed(
val errorCode = intFromBuff(bytes, 0, 1)
if (errorCode != 2) {
failed = true
aapsLogger.debug(LTag.PUMPBTCOMM, "Messsage response: $errorCode FAILED!!")
aapsLogger.debug(LTag.PUMPBTCOMM, "Message response: $errorCode FAILED!!")
} else {
failed = false
aapsLogger.debug(LTag.PUMPBTCOMM, "Messsage response: $errorCode OK")
aapsLogger.debug(LTag.PUMPBTCOMM, "Message response: $errorCode OK")
}
danaPump.bolusStartErrorCode = errorCode
}

View file

@ -1,14 +1,13 @@
package info.nightscout.androidaps.danar.comm
import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.rx.logging.LTag
class MsgSetExtendedBolusStart(
injector: HasAndroidInjector,
private var amount: Double,
private var halfhours: Byte
private var halfHours: Byte
) : MessageBase(injector) {
@ -16,12 +15,12 @@ class MsgSetExtendedBolusStart(
setCommand(0x0407)
aapsLogger.debug(LTag.PUMPBTCOMM, "New message")
// HARDCODED LIMITS
if (halfhours < 1) halfhours = 1
if (halfhours > 16) halfhours = 16
amount = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
if (halfHours < 1) halfHours = 1
if (halfHours > 16) halfHours = 16
amount = constraintChecker.applyBolusConstraints(ConstraintObject(amount, injector)).value()
addParamInt((amount * 100).toInt())
addParamByte(halfhours)
aapsLogger.debug(LTag.PUMPBTCOMM, "Set extended bolus start: " + (amount * 100).toInt() / 100.0 + "U halfhours: " + halfhours.toInt())
addParamByte(halfHours)
aapsLogger.debug(LTag.PUMPBTCOMM, "Set extended bolus start: " + (amount * 100).toInt() / 100.0 + "U halfHours: " + halfHours.toInt())
}
override fun handleMessage(bytes: ByteArray) {

View file

@ -3,9 +3,8 @@ package info.nightscout.pump.danaR
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.PumpSync
@ -22,7 +21,7 @@ import org.mockito.Mockito.`when`
class DanaRPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var pumpSync: PumpSync
@Mock lateinit var instantiator: Instantiator
@ -34,7 +33,11 @@ class DanaRPluginTest : TestBaseWithProfile() {
private lateinit var danaRPlugin: DanaRPlugin
val injector = HasAndroidInjector {
AndroidInjector { }
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@BeforeEach
@ -57,11 +60,11 @@ class DanaRPluginTest : TestBaseWithProfile() {
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHBASALRATE)
val c = ConstraintObject(Double.MAX_VALUE, injector)
danaRPlugin.applyBasalConstraints(c, validProfile)
Assertions.assertEquals(0.8, c.value(), 0.01)
Assertions.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons())
Assertions.assertEquals("DanaR: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons())
}
@Test @Throws(Exception::class)
@ -69,10 +72,10 @@ class DanaRPluginTest : TestBaseWithProfile() {
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHPERCENTBASALRATE)
val c = ConstraintObject(Int.MAX_VALUE, injector)
danaRPlugin.applyBasalPercentConstraints(c, validProfile)
Assertions.assertEquals(200, c.value())
Assertions.assertEquals("DanaR: Limiting max percent rate to 200% because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaR: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaR: Limiting max percent rate to 200% because of pump limit", c.getReasons())
Assertions.assertEquals("DanaR: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons())
}
}

View file

@ -6,8 +6,9 @@ import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danar.comm.MessageBase
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.PumpSync
@ -15,7 +16,6 @@ import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.dana.DanaPump
import info.nightscout.pump.dana.database.DanaHistoryRecordDao
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.BeforeEach
import org.mockito.ArgumentMatchers
@ -32,7 +32,7 @@ open class DanaRTestBase : TestBaseWithProfile() {
@Mock lateinit var configBuilder: ConfigBuilder
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var pumpSync: PumpSync
@Mock lateinit var danaHistoryRecordDao: DanaHistoryRecordDao
@Mock lateinit var instantiator: Instantiator
@ -50,6 +50,9 @@ open class DanaRTestBase : TestBaseWithProfile() {
val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is MessageBase) {
it.aapsLogger = aapsLogger
it.dateUtil = dateUtil
@ -57,7 +60,7 @@ open class DanaRTestBase : TestBaseWithProfile() {
it.danaRPlugin = danaRPlugin
it.danaRKoreanPlugin = danaRKoreanPlugin
it.danaRv2Plugin = danaRv2Plugin
it.rxBus = RxBus(aapsSchedulers, aapsLogger)
it.rxBus = rxBus
it.rh = rh
it.activePlugin = activePlugin
it.configBuilder = configBuilder

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MessageHashTableR
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.Mockito
@ -9,7 +9,7 @@ import org.mockito.Mockito
class MessageHashTableRTest : DanaRTestBase() {
@Test fun runTest() {
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val messageHashTable = MessageHashTableR(injector)
val testMessage = messageHashTable.findMessage(0x41f2)
Assertions.assertEquals("CMD_HISTORY_ALL", testMessage.messageName)

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgBolusStart
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when`
@ -9,7 +9,7 @@ import org.mockito.Mockito.`when`
class MsgBolusStartTest : DanaRTestBase() {
@Test fun runTest() {
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val packet = MsgBolusStart(injector, 1.0)
// test message decoding

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgBolusStartWithSpeed
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.Mockito
@ -9,7 +9,7 @@ import org.mockito.Mockito
class MsgBolusStartWithSpeedTest : DanaRTestBase() {
@Test fun runTest() {
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val packet = MsgBolusStartWithSpeed(injector, 0.0, 0)
// test message decoding

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgSetExtendedBolusStart
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when`
@ -9,7 +9,7 @@ import org.mockito.Mockito.`when`
class MsgSetExtendedBolusStartTest : DanaRTestBase() {
@Test fun runTest() {
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val packet = MsgSetExtendedBolusStart(injector, 2.0, 2.toByte())
// test message decoding

View file

@ -3,9 +3,8 @@ package info.nightscout.pump.danaRKorean
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.PumpSync
@ -22,7 +21,7 @@ import org.mockito.Mockito.`when`
class DanaRKoreanPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var pumpSync: PumpSync
@Mock lateinit var instantiator: Instantiator
@ -34,7 +33,11 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() {
private lateinit var danaRPlugin: DanaRKoreanPlugin
val injector = HasAndroidInjector {
AndroidInjector { }
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@BeforeEach
@ -57,11 +60,11 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() {
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHBASALRATE)
val c = ConstraintObject(Double.MAX_VALUE, injector)
danaRPlugin.applyBasalConstraints(c, validProfile)
Assertions.assertEquals(0.8, c.value(), 0.01)
Assertions.assertEquals("DanaRKorean: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaRKorean: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaRKorean: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons())
Assertions.assertEquals("DanaRKorean: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons())
}
@Test @Throws(Exception::class)
@ -69,10 +72,10 @@ class DanaRKoreanPluginTest : TestBaseWithProfile() {
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaRPlugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHPERCENTBASALRATE)
val c = ConstraintObject(Int.MAX_VALUE, injector)
danaRPlugin.applyBasalPercentConstraints(c, validProfile)
Assertions.assertEquals(200, c.value())
Assertions.assertEquals("DanaRKorean: Limiting max percent rate to 200% because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaRKorean: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaRKorean: Limiting max percent rate to 200% because of pump limit", c.getReasons())
Assertions.assertEquals("DanaRKorean: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons())
}
}

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaRKorean.comm
import info.nightscout.androidaps.danaRKorean.comm.MessageHashTableRKorean
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.pump.danaR.comm.DanaRTestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
@ -10,7 +10,7 @@ import org.mockito.Mockito
class MessageHashTableRKoreanTest : DanaRTestBase() {
@Test fun runTest() {
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
Mockito.`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val messageHashTable = MessageHashTableRKorean(injector)
val testMessage = messageHashTable.findMessage(0x41f2)
Assertions.assertEquals("CMD_HISTORY_ALL", testMessage.messageName)

View file

@ -3,9 +3,8 @@ package info.nightscout.pump.danaRv2
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
@ -24,7 +23,7 @@ import org.mockito.Mockito.`when`
class DanaRv2PluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage
@ -38,7 +37,11 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
private lateinit var danaRv2Plugin: DanaRv2Plugin
val injector = HasAndroidInjector {
AndroidInjector { }
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@BeforeEach
@ -61,11 +64,11 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHBASALRATE)
val c = ConstraintObject(Double.MAX_VALUE, injector)
danaRv2Plugin.applyBasalConstraints(c, validProfile)
Assertions.assertEquals(0.8, c.value(), 0.01)
Assertions.assertEquals("DanaRv2: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaRv2: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaRv2: Limiting max basal rate to 0.80 U/h because of pump limit", c.getReasons())
Assertions.assertEquals("DanaRv2: Limiting max basal rate to 0.80 U/h because of pump limit", c.getMostLimitedReasons())
}
@Test
@ -73,10 +76,10 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHPERCENTBASALRATE)
val c = ConstraintObject(Int.MAX_VALUE, injector)
danaRv2Plugin.applyBasalPercentConstraints(c, validProfile)
Assertions.assertEquals(200, c.value())
Assertions.assertEquals("DanaRv2: Limiting max percent rate to 200% because of pump limit", c.getReasons(aapsLogger))
Assertions.assertEquals("DanaRv2: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons(aapsLogger))
Assertions.assertEquals("DanaRv2: Limiting max percent rate to 200% because of pump limit", c.getReasons())
Assertions.assertEquals("DanaRv2: Limiting max percent rate to 200% because of pump limit", c.getMostLimitedReasons())
}
}

View file

@ -3,7 +3,7 @@ package info.nightscout.pump.danaRv2.comm
import info.nightscout.androidaps.danaRv2.comm.MessageHashTableRv2
import info.nightscout.androidaps.danaRv2.comm.MsgStatusAPS_v2
import info.nightscout.androidaps.danar.comm.MessageBase
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.pump.danaR.comm.DanaRTestBase
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
@ -13,7 +13,7 @@ class MessageHashTableRv2Test : DanaRTestBase() {
@Test
fun runTest() {
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val messageHashTableRv2 = MessageHashTableRv2(injector)
val forTesting: MessageBase = MsgStatusAPS_v2(injector)
val testPacket: MessageBase = messageHashTableRv2.findMessage(forTesting.command)

View file

@ -8,10 +8,12 @@ import android.os.IBinder
import android.text.format.DateFormat
import androidx.preference.Preference
import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.OwnDatabasePlugin
import info.nightscout.interfaces.plugin.PluginDescription
@ -68,7 +70,7 @@ class DanaRSPlugin @Inject constructor(
private val rxBus: RxBus,
private val context: Context,
rh: ResourceHelper,
private val constraintChecker: Constraints,
private val constraintChecker: ConstraintsChecker,
private val profileFunction: ProfileFunction,
private val sp: SP,
commandQueue: CommandQueue,
@ -92,7 +94,7 @@ class DanaRSPlugin @Inject constructor(
.preferencesId(R.xml.pref_danars)
.description(info.nightscout.pump.dana.R.string.description_pump_dana_rs),
injector, aapsLogger, rh, commandQueue
), Pump, Dana, Constraints, OwnDatabasePlugin {
), Pump, Dana, PluginConstraints, OwnDatabasePlugin {
private val disposable = CompositeDisposable()
private var danaRSService: DanaRSService? = null
@ -202,18 +204,22 @@ class DanaRSPlugin @Inject constructor(
// Constraints interface
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
absoluteRate.setIfSmaller(aapsLogger, danaPump.maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, danaPump.maxBasal, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
absoluteRate.setIfSmaller(danaPump.maxBasal, rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, danaPump.maxBasal, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
return absoluteRate
}
override fun applyBasalPercentConstraints(percentRate: Constraint<Int>, profile: Profile): Constraint<Int> {
percentRate.setIfGreater(aapsLogger, 0, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
percentRate.setIfSmaller(aapsLogger, pumpDescription.maxTempPercent, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, pumpDescription.maxTempPercent, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
percentRate.setIfGreater(0, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, 0, rh.gs(info.nightscout.core.ui.R.string.itmustbepositivevalue)), this)
percentRate.setIfSmaller(
pumpDescription.maxTempPercent,
rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, pumpDescription.maxTempPercent, rh.gs(info.nightscout.core.ui.R.string.pumplimit)),
this
)
return percentRate
}
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
insulin.setIfSmaller(aapsLogger, danaPump.maxBolus, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, danaPump.maxBolus, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
insulin.setIfSmaller(danaPump.maxBolus, rh.gs(info.nightscout.core.ui.R.string.limitingbolus, danaPump.maxBolus, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this)
return insulin
}
@ -282,7 +288,7 @@ class DanaRSPlugin @Inject constructor(
@Synchronized
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)).value()
detailedBolusInfo.insulin = constraintChecker.applyBolusConstraints(ConstraintObject(detailedBolusInfo.insulin, injector)).value()
return if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
val preferencesSpeed = sp.getInt(info.nightscout.pump.dana.R.string.key_danars_bolusspeed, 0)
var speed = 12
@ -337,7 +343,7 @@ class DanaRSPlugin @Inject constructor(
// This is called from APS
@Synchronized
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
val absoluteAfterConstrain = constraintChecker.applyBasalConstraints(Constraint(absoluteRate), profile).value()
val absoluteAfterConstrain = constraintChecker.applyBasalConstraints(ConstraintObject(absoluteRate, injector), profile).value()
var doTempOff = baseBasalRate - absoluteAfterConstrain == 0.0
val doLowTemp = absoluteAfterConstrain < baseBasalRate
val doHighTemp = absoluteAfterConstrain > baseBasalRate
@ -413,7 +419,7 @@ class DanaRSPlugin @Inject constructor(
@Synchronized
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult {
val result = PumpEnactResult(injector)
var percentAfterConstraint = constraintChecker.applyBasalPercentConstraints(Constraint(percent), profile).value()
var percentAfterConstraint = constraintChecker.applyBasalPercentConstraints(ConstraintObject(percent, injector), profile).value()
if (percentAfterConstraint < 0) {
result.isTempCancel = false
result.enacted = false
@ -483,7 +489,7 @@ class DanaRSPlugin @Inject constructor(
@Synchronized
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
var insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
var insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(ConstraintObject(insulin, injector)).value()
// needs to be rounded
val durationInHalfHours = max(durationInMinutes / 30, 1)
insulinAfterConstraint = Round.roundTo(insulinAfterConstraint, pumpDescription.extendedBolusStep)

View file

@ -2,8 +2,8 @@ package info.nightscout.pump.danars.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danars.encryption.BleEncryption
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.pump.dana.DanaPump
import info.nightscout.rx.logging.LTag
import javax.inject.Inject
@ -15,13 +15,13 @@ class DanaRSPacketBolusSetStepBolusStart(
) : DanaRSPacket(injector) {
@Inject lateinit var danaPump: DanaPump
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
init {
opCode = BleEncryption.DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_START
// Speed 0 => 12 sec/U, 1 => 30 sec/U, 2 => 60 sec/U
// HARDCODED LIMIT - if there is one that could be created
amount = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
amount = constraintChecker.applyBolusConstraints(ConstraintObject(amount, injector)).value()
aapsLogger.debug(LTag.PUMPCOMM, "Bolus start : $amount speed: $speed")
}

View file

@ -10,7 +10,7 @@ import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile
@ -103,7 +103,7 @@ class DanaRSService : DaggerService() {
@Inject lateinit var danaRSPlugin: DanaRSPlugin
@Inject lateinit var danaPump: DanaPump
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var constraintChecker: Constraints
@Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var bleComm: BLEComm
@Inject lateinit var fabricPrivacy: FabricPrivacy

Some files were not shown because too many files have changed in this diff Show more