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 android.annotation.SuppressLint
import info.nightscout.rx.AapsSchedulers 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 info.nightscout.sharedtests.rx.TestAapsSchedulers
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
@ -19,11 +21,13 @@ open class TestBase {
val aapsLogger = AAPSLoggerTest() val aapsLogger = AAPSLoggerTest()
val aapsSchedulers: AapsSchedulers = TestAapsSchedulers() val aapsSchedulers: AapsSchedulers = TestAapsSchedulers()
lateinit var rxBus: RxBus
@BeforeEach @BeforeEach
fun setupLocale() { fun setupLocale() {
Locale.setDefault(Locale.ENGLISH) Locale.setDefault(Locale.ENGLISH)
System.setProperty("disableFirebase", "true") System.setProperty("disableFirebase", "true")
rxBus = RxBusImpl(aapsSchedulers, aapsLogger)
} }
@SuppressLint("CheckResult") @SuppressLint("CheckResult")

View file

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

View file

@ -1,102 +1,98 @@
package info.nightscout.androidaps package info.nightscout.androidaps
import androidx.test.ext.junit.runners.AndroidJUnit4 //@LargeTest
import androidx.test.filters.LargeTest //@RunWith(AndroidJUnit4::class)
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
class RealPumpTest { class RealPumpTest {
/* /*
companion object { companion object {
const val R_PASSWORD = 1234 const val R_PASSWORD = 1234
const val R_SERIAL = "PBB00013LR_P" 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)
} }
while (true) { 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\"}"
//log.debug("Tick")
SystemClock.sleep(1000) @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 package info.nightscout.androidaps
import androidx.test.ext.junit.runners.AndroidJUnit4 //@LargeTest
import androidx.test.filters.LargeTest //@RunWith(AndroidJUnit4::class)
import org.junit.runner.RunWith
@LargeTest
@RunWith(AndroidJUnit4::class)
class SetupWizardActivityTest { class SetupWizardActivityTest {
/* /*
@Rule @Rule
@JvmField @JvmField
var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java) var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java)
@Rule @Rule
@JvmField @JvmField
var mGrantPermissionRule: GrantPermissionRule = var mGrantPermissionRule: GrantPermissionRule =
GrantPermissionRule.grant( GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE android.Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
@Before @Before
fun clear() { fun clear() {
sp.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())
} }
// Store permission /*
askButton = onView(withText("Ask for permission"))
if (askButton.isDisplayed()) { To run from command line
askButton.perform(scrollTo(), click()) gradlew connectedFullDebugAndroidTest
onView(withText("OK")).perform(click())
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()) onView(withId(R.id.next_button)).waitAndPerform(click())
} // Agreement page
// Import settings : skip of found onView(withText("I UNDERSTAND AND AGREE")).perform(scrollTo(), click())
askButton = onView(withText("IMPORT SETTINGS"))
if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).waitAndPerform(click()) onView(withId(R.id.next_button)).waitAndPerform(click())
} // Location permission
// Units selection var askButton = onView(withText("Ask for permission"))
onView(withText("mmol/L")).perform(scrollTo(), click()) if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).perform(click()) askButton.perform(scrollTo(), click())
// Display target selection onView(withId(R.id.next_button)).waitAndPerform(click())
onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5")) }
onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11")) // Store permission
onView(withId(R.id.next_button)).perform(click()) askButton = onView(withText("Ask for permission"))
// NSClient if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).perform(click()) askButton.perform(scrollTo(), click())
// Age selection onView(withText("OK")).perform(click())
onView(withText("Adult")).perform(scrollTo(), click()) onView(withId(R.id.next_button)).waitAndPerform(click())
onView(withId(R.id.next_button)).waitAndPerform(click()) }
// Insulin selection // Import settings : skip of found
onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click()) askButton = onView(withText("IMPORT SETTINGS"))
onView(withId(R.id.next_button)).waitAndPerform(click()) if (askButton.isDisplayed()) {
// BG source selection onView(withId(R.id.next_button)).waitAndPerform(click())
onView(withText("Random BG")).perform(scrollTo(), click()) }
onView(withId(R.id.next_button)).waitAndPerform(click()) // Units selection
// Profile selection onView(withText("mmol/L")).perform(scrollTo(), click())
onView(withText("Local Profile")).perform(scrollTo(), click()) onView(withId(R.id.next_button)).perform(click())
onView(withId(R.id.next_button)).waitAndPerform(click()) // Display target selection
// Local profile - DIA onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5"))
onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0")) onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11"))
// Local profile - IC onView(withId(R.id.next_button)).perform(click())
onView(withId(R.id.ic_tab)).perform(scrollTo(), click()) // NSClient
onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed())) onView(withId(R.id.next_button)).perform(click())
.perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard()) // Age selection
// Local profile - ISF onView(withText("Adult")).perform(scrollTo(), click())
onView(withId(R.id.isf_tab)).perform(scrollTo(), click()) onView(withId(R.id.next_button)).waitAndPerform(click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed())) // Insulin selection
.perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard()) onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click())
// Local profile - BAS onView(withId(R.id.next_button)).waitAndPerform(click())
onView(withId(R.id.basal_tab)).perform(scrollTo(), click()) // BG source selection
onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2)) onView(withText("Random BG")).perform(scrollTo(), click())
.perform(scrollTo(), click()) onView(withId(R.id.next_button)).waitAndPerform(click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed())) // Profile selection
.perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard()) onView(withText("Local Profile")).perform(scrollTo(), click())
onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed())) onView(withId(R.id.next_button)).waitAndPerform(click())
.perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard()) // Local profile - DIA
onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0))) onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0"))
.perform(scrollTo(), click()) // Local profile - IC
onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13) onView(withId(R.id.ic_tab)).perform(scrollTo(), click())
.perform(click()) onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed()))
// Local profile - TARGET .perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard())
onView(withId(R.id.target_tab)).perform(scrollTo(), click()) // Local profile - ISF
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-1-0")), isDisplayed())) onView(withId(R.id.isf_tab)).perform(scrollTo(), click())
.perform(ViewActions.replaceText("6"), ViewActions.closeSoftKeyboard()) onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed()))
onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-2-0")), isDisplayed())) .perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard())
.perform(ViewActions.replaceText("6.5"), ViewActions.closeSoftKeyboard()) // Local profile - BAS
onView(withText("Save")).perform(scrollTo(), click()) onView(withId(R.id.basal_tab)).perform(scrollTo(), click())
onView(Matchers.allOf(withId(R.id.localprofile_profileswitch), isDisplayed())) onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2))
.perform(scrollTo(), click()) .perform(scrollTo(), click())
onView(allOf(withId(R.id.ok), isDisplayed())).perform(click()) onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed()))
// confirm dialog .perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard())
//onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed()))
clickOkInDialog() .perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard())
onView(withId(R.id.next_button)).waitAndPerform(click()) onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0)))
// Profile switch .perform(scrollTo(), click())
askButton = onView(withText("Do Profile Switch")) onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13)
if (askButton.isDisplayed()) { .perform(click())
askButton.perform(scrollTo(), 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(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() clickOkInDialog()
while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
onView(withId(R.id.next_button)).waitAndPerform(click()) onView(withId(R.id.next_button)).waitAndPerform(click())
} // Profile switch
// Pump askButton = onView(withText("Do Profile Switch"))
onView(withText("Virtual Pump")).perform(scrollTo(), click()) if (askButton.isDisplayed()) {
onView(withId(R.id.next_button)).waitAndPerform(click()) askButton.perform(scrollTo(), click())
// APS onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
onView(withText("OpenAPS SMB")).perform(scrollTo(), click()) // onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
onView(withId(R.id.next_button)).waitAndPerform(click()) clickOkInDialog()
// Open Closed Loop while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
onView(withText("Closed Loop")).perform(scrollTo(), click()) onView(withId(R.id.next_button)).waitAndPerform(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)
} }
// 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 { // Verify settings
val parent = view.parent Assert.assertEquals(Constants.MMOL, ProfileFunctions.getSystemUnits())
return parent is ViewGroup && parentMatcher.matches(parent) Assert.assertEquals(17.0, HardLimits.maxBolus(), 0.0001) // Adult
&& view == parent.getChildAt(position) 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.AndroidPermission
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.aps.Loop 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.logging.UserEntryLogger
import info.nightscout.interfaces.maintenance.PrefFileListProvider import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
@ -96,7 +96,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var iconsProvider: IconsProvider @Inject lateinit var iconsProvider: IconsProvider
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin @Inject lateinit var signatureVerifierPlugin: SignatureVerifierPlugin
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var profileFunction: ProfileFunction @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.plugin.PluginBase
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils 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.overview.notifications.NotificationStore
import info.nightscout.plugins.general.themes.ThemeSwitcherPlugin import info.nightscout.plugins.general.themes.ThemeSwitcherPlugin
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
@ -77,7 +78,7 @@ class MainApp : DaggerApplication() {
@Inject lateinit var compatDBHelper: CompatDBHelper @Inject lateinit var compatDBHelper: CompatDBHelper
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil @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 uel: UserEntryLogger
@Inject lateinit var uiInteraction: UiInteraction @Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var notificationStore: NotificationStore @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.database.impl.AppRepository
import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.sdk.interfaces.RunningConfiguration import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.ActivePlugin 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.receivers.ReceiverStatusStore
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.pump.virtual.VirtualPumpPlugin 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.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
@ -34,8 +33,7 @@ import org.mockito.Mockito.`when`
class LoopPluginTest : TestBase() { class LoopPluginTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger) @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var rh: ResourceHelper @Mock lateinit var rh: ResourceHelper
@Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var context: Context @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.protection.ProtectionCheck
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
@ -37,6 +36,6 @@ class ConfigBuilderPluginTest : TestBase() {
@BeforeEach @BeforeEach
fun prepareMock() { 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.InsightDatabaseDao
import info.nightscout.androidaps.insight.database.InsightDbHelper import info.nightscout.androidaps.insight.database.InsightDbHelper
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.implementation.iob.GlucoseStatusProviderImpl import info.nightscout.implementation.iob.GlucoseStatusProviderImpl
import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.constraints.Objectives import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.maintenance.PrefFileListProvider import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
@ -74,7 +75,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
private lateinit var danaPump: DanaPump private lateinit var danaPump: DanaPump
private lateinit var insightDbHelper: InsightDbHelper private lateinit var insightDbHelper: InsightDbHelper
private lateinit var constraintChecker: ConstraintsImpl private lateinit var constraintChecker: ConstraintsCheckerImpl
private lateinit var safetyPlugin: SafetyPlugin private lateinit var safetyPlugin: SafetyPlugin
private lateinit var objectivesPlugin: ObjectivesPlugin private lateinit var objectivesPlugin: ObjectivesPlugin
private lateinit var comboPlugin: ComboPlugin private lateinit var comboPlugin: ComboPlugin
@ -94,6 +95,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
if (it is PumpEnactResult) { if (it is PumpEnactResult) {
it.context = context 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("") `when`(sp.getString(R.string.key_danar_bt_name, "")).thenReturn("")
//SafetyPlugin //SafetyPlugin
constraintChecker = ConstraintsImpl(activePlugin) constraintChecker = ConstraintsCheckerImpl(activePlugin, injector)
val glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculator, dateUtil, decimalFormatter) val glucoseStatusProvider = GlucoseStatusProviderImpl(aapsLogger, iobCobCalculator, dateUtil, decimalFormatter)
@ -226,7 +230,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
constraintsPluginsList.add(insightPlugin) constraintsPluginsList.add(insightPlugin)
constraintsPluginsList.add(openAPSAMAPlugin) constraintsPluginsList.add(openAPSAMAPlugin)
constraintsPluginsList.add(openAPSSMBPlugin) constraintsPluginsList.add(openAPSSMBPlugin)
`when`(activePlugin.getSpecificPluginsListByInterface(Constraints::class.java)).thenReturn(constraintsPluginsList) `when`(activePlugin.getSpecificPluginsListByInterface(PluginConstraints::class.java)).thenReturn(constraintsPluginsList)
objectivesPlugin.onStart() objectivesPlugin.onStart()
} }
@ -268,7 +272,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val c = constraintChecker.isAutosensModeEnabled() val c = constraintChecker.isAutosensModeEnabled()
assertThat(c.reasonList).hasSize(2) // Safety & Objectives assertThat(c.reasonList).hasSize(2) // Safety & Objectives
assertThat(c.mostLimitedReasonList).hasSize(2) // Safety & Objectives assertThat(c.mostLimitedReasonList).hasSize(2) // Safety & Objectives
assertThat( c.value()).isFalse() assertThat(c.value()).isFalse()
} }
// Safety // Safety
@ -278,7 +282,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val c = constraintChecker.isAdvancedFilteringEnabled() val c = constraintChecker.isAdvancedFilteringEnabled()
assertThat(c.reasonList).hasSize(1) // Safety assertThat(c.reasonList).hasSize(1) // Safety
assertThat(c.mostLimitedReasonList).hasSize(1) // Safety assertThat(c.mostLimitedReasonList).hasSize(1) // Safety
assertThat( c.value()).isFalse() assertThat(c.value()).isFalse()
} }
// SMB should limit // SMB should limit
@ -286,7 +290,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
fun isSuperBolusEnabledTest() { fun isSuperBolusEnabledTest() {
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
val c = constraintChecker.isSuperBolusEnabled() val c = constraintChecker.isSuperBolusEnabled()
assertThat( c.value()).isFalse() // SMB should limit assertThat(c.value()).isFalse() // SMB should limit
} }
// Safety & Objectives // Safety & Objectives
@ -296,11 +300,11 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0 objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false) `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`(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() val c = constraintChecker.isSMBModeEnabled()
assertThat(c.reasonList).hasSize(3) // 2x Safety & Objectives assertThat(c.reasonList).hasSize(3) // 2x Safety & Objectives
assertThat(c.mostLimitedReasonList).hasSize(3) // 2x Safety & Objectives assertThat(c.mostLimitedReasonList).hasSize(3) // 2x Safety & Objectives
assertThat( c.value()).isFalse() assertThat(c.value()).isFalse()
} }
// applyBasalConstraints tests // applyBasalConstraints tests
@ -326,9 +330,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits // Apply all limits
val d = constraintChecker.getMaxBasalAllowed(validProfile) 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.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 @Test
@ -355,7 +359,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val i = constraintChecker.getMaxBasalPercentAllowed(validProfile) val i = constraintChecker.getMaxBasalPercentAllowed(validProfile)
assertThat(i.value()).isEqualTo(200) assertThat(i.value()).isEqualTo(200)
assertThat(i.reasonList).hasSize(6) 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 // applyBolusConstraints tests
@ -380,9 +384,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits // Apply all limits
val d = constraintChecker.getMaxBolusAllowed() 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.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 // applyCarbsConstraints tests
@ -395,7 +399,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
val i = constraintChecker.getMaxCarbsAllowed() val i = constraintChecker.getMaxCarbsAllowed()
assertThat(i.value()).isEqualTo(48) assertThat(i.value()).isEqualTo(48)
assertThat(i.reasonList).hasSize(1) 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 // applyMaxIOBConstraints tests
@ -410,9 +414,9 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits // Apply all limits
val d = constraintChecker.getMaxIOBAllowed() 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.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 @Test
@ -426,8 +430,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
// Apply all limits // Apply all limits
val d = constraintChecker.getMaxIOBAllowed() 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.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 com.google.common.truth.Truth.assertThat
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.ApsMode
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatusProvider import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profiling.Profiler import info.nightscout.interfaces.profiling.Profiler
@ -29,7 +29,7 @@ import org.mockito.Mockito.`when`
class SafetyPluginTest : TestBaseWithProfile() { class SafetyPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Mock lateinit var glimpPlugin: GlimpPlugin @Mock lateinit var glimpPlugin: GlimpPlugin
@Mock lateinit var profiler: Profiler @Mock lateinit var profiler: Profiler
@ -43,7 +43,13 @@ class SafetyPluginTest : TestBaseWithProfile() {
private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin 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() private val pumpDescription = PumpDescription()
@BeforeEach @BeforeEach
@ -86,9 +92,8 @@ class SafetyPluginTest : TestBaseWithProfile() {
@Test @Test
fun pumpDescriptionShouldLimitLoopInvocation() { fun pumpDescriptionShouldLimitLoopInvocation() {
pumpDescription.isTempBasalCapable = false pumpDescription.isTempBasalCapable = false
var c = Constraint(true) val c = safetyPlugin.isLoopInvocationAllowed(ConstraintObject(true, injector))
c = safetyPlugin.isLoopInvocationAllowed(c) assertThat(c.getReasons()).isEqualTo("Safety: Pump is not temp basal capable")
assertThat(c.getReasons(aapsLogger)).isEqualTo("Safety: Pump is not temp basal capable")
assertThat(c.value()).isFalse() assertThat(c.value()).isFalse()
} }
@ -96,47 +101,42 @@ class SafetyPluginTest : TestBaseWithProfile() {
fun disabledEngineeringModeShouldLimitClosedLoop() { fun disabledEngineeringModeShouldLimitClosedLoop() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name)
`when`(config.isEngineeringModeOrRelease()).thenReturn(false) `when`(config.isEngineeringModeOrRelease()).thenReturn(false)
var c = Constraint(true) val c = safetyPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
c = safetyPlugin.isClosedLoopAllowed(c) assertThat(c.getReasons()).contains("Running dev version. Closed loop is disabled.")
assertThat(c.getReasons(aapsLogger)).contains("Running dev version. Closed loop is disabled.")
assertThat(c.value()).isFalse() assertThat(c.value()).isFalse()
} }
@Test @Test
fun setOpenLoopInPreferencesShouldLimitClosedLoop() { fun setOpenLoopInPreferencesShouldLimitClosedLoop() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name) `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name)
var c = Constraint(true) val c = safetyPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
c = safetyPlugin.isClosedLoopAllowed(c) assertThat(c.getReasons()).contains("Closed loop mode disabled in preferences")
assertThat(c.getReasons(aapsLogger)).contains("Closed loop mode disabled in preferences")
assertThat(c.value()).isFalse() assertThat(c.value()).isFalse()
} }
@Test @Test
fun notEnabledSMBInPreferencesDisablesSMB() { fun notEnabledSMBInPreferencesDisablesSMB() {
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false) `when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false)
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(true)) `when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(ConstraintObject(true, injector))
var c = Constraint(true) val c = openAPSSMBPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
c = openAPSSMBPlugin.isSMBModeEnabled(c) assertThat(c.getReasons()).contains("SMB disabled in preferences")
assertThat(c.getReasons(aapsLogger)).contains("SMB disabled in preferences")
assertThat(c.value()).isFalse() assertThat(c.value()).isFalse()
} }
@Test @Test
fun openLoopPreventsSMB() { fun openLoopPreventsSMB() {
`when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(true) `when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(true)
`when`(constraintChecker.isClosedLoopAllowed(anyObject())).thenReturn(Constraint(false)) `when`(constraintChecker.isClosedLoopAllowed()).thenReturn(ConstraintObject(false, injector))
var c = Constraint(true) val c = safetyPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
c = safetyPlugin.isSMBModeEnabled(c) assertThat(c.getReasons()).contains("SMB not allowed in open loop mode")
assertThat(c.getReasons(aapsLogger)).contains("SMB not allowed in open loop mode")
assertThat(c.value()).isFalse() assertThat(c.value()).isFalse()
} }
@Test @Test
fun bgSourceShouldPreventSMBAlways() { fun bgSourceShouldPreventSMBAlways() {
`when`(activePlugin.activeBgSource).thenReturn(glimpPlugin) `when`(activePlugin.activeBgSource).thenReturn(glimpPlugin)
var c = Constraint(true) val c = safetyPlugin.isAdvancedFilteringEnabled(ConstraintObject(true, injector))
c = safetyPlugin.isAdvancedFilteringEnabled(c) assertThat(c.getReasons()).isEqualTo("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering")
assertThat(c.getReasons(aapsLogger)).isEqualTo("Safety: SMB always and after carbs disabled because active BG source doesn\\'t support advanced filtering")
assertThat(c.value()).isFalse() 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_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.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") `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) safetyPlugin.applyBasalConstraints(c, validProfile)
assertThat(c.value()).isWithin(0.01).of(2.0) 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 Safety: Limiting max basal rate to 2.00 U/h because of hard limit
""".trimIndent()) """.trimIndent()
assertThat(c.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting max basal rate to 2.00 U/h because of hard limit") )
assertThat(c.getMostLimitedReasons()).isEqualTo("Safety: Limiting max basal rate to 2.00 U/h because of hard limit")
} }
@Test @Test
fun doNotAllowNegativeBasalRate() { fun doNotAllowNegativeBasalRate() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child") `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) safetyPlugin.applyBasalConstraints(d, validProfile)
assertThat(d.value()).isWithin(0.01).of(0.0) assertThat(d.value()).isWithin(0.01).of(0.0)
assertThat(d.getReasons(aapsLogger)).isEqualTo( assertThat(d.getReasons()).isEqualTo(
"Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value") "Safety: Limiting max basal rate to 0.00 U/h because of it must be positive value"
)
} }
@Test @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_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.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") `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) safetyPlugin.applyBasalPercentConstraints(i, validProfile)
assertThat(i.value()).isEqualTo(200) 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 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 percent rate to 200% because of pump limit
Safety: Limiting max basal rate to 500.00 U/h because of pump limit Safety: Limiting max basal rate to 500.00 U/h because of pump limit
""".trimIndent() """.trimIndent()
) )
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo( assertThat(i.getMostLimitedReasons()).isEqualTo(
"Safety: Limiting max percent rate to 200% because of pump limit") "Safety: Limiting max percent rate to 200% because of pump limit"
)
} }
@Test @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.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") `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
val i = Constraint(Constants.REALLYHIGHBASALRATE) val i = ConstraintObject(Double.MAX_VALUE, injector)
openAPSSMBPlugin.applyBasalConstraints(i, validProfile) openAPSSMBPlugin.applyBasalConstraints(i, validProfile)
assertThat(i.value()).isWithin(0.01).of(1.0) 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 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 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 OpenAPSSMB: Limiting max basal rate to 3.00 U/h because of max daily basal multiplier
""".trimIndent()) """.trimIndent()
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences") )
assertThat(i.getMostLimitedReasons()).isEqualTo("OpenAPSSMB: Limiting max basal rate to 1.00 U/h because of max value in preferences")
} }
@Test @Test
fun doNotAllowNegativePercentBasalRate() { fun doNotAllowNegativePercentBasalRate() {
`when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child") `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) safetyPlugin.applyBasalPercentConstraints(i, validProfile)
assertThat(i.value()).isEqualTo(0) 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: 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 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 Safety: Limiting max percent rate to 0% because of pump limit
""".trimIndent()) """.trimIndent()
assertThat(i.getMostLimitedReasons(aapsLogger)).isEqualTo("Safety: Limiting max percent rate to 0% because of pump limit") )
assertThat(i.getMostLimitedReasons()).isEqualTo("Safety: Limiting max percent rate to 0% because of pump limit")
} }
@Test @Test
fun bolusAmountShouldBeLimited() { fun bolusAmountShouldBeLimited() {
`when`(sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0) `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") `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
var d = Constraint(Constants.REALLYHIGHBOLUS) val d = safetyPlugin.applyBolusConstraints(ConstraintObject(Double.MAX_VALUE, injector))
d = safetyPlugin.applyBolusConstraints(d)
assertThat(d.value()).isWithin(0.01).of(3.0) 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 3.0 U because of max value in preferences
Safety: Limiting bolus to 5.0 U because of hard limit Safety: Limiting bolus to 5.0 U because of hard limit
""".trimIndent()) """.trimIndent()
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")
} }
@Test @Test
fun doNotAllowNegativeBolusAmount() { fun doNotAllowNegativeBolusAmount() {
`when`(sp.getDouble(info.nightscout.core.utils.R.string.key_treatmentssafety_maxbolus, 3.0)).thenReturn(3.0) `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") `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("child")
var d = Constraint(-22.0) val d = safetyPlugin.applyBolusConstraints(ConstraintObject(-22.0, injector))
d = safetyPlugin.applyBolusConstraints(d)
assertThat(d.value()).isWithin(0.01).of(0.0) 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.getReasons()).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.getMostLimitedReasons()).isEqualTo("Safety: Limiting bolus to 0.0 U because of it must be positive value")
} }
@Test @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) `when`(sp.getInt(info.nightscout.core.utils.R.string.key_treatmentssafety_maxcarbs, 48)).thenReturn(48)
// Negative carbs not allowed // Negative carbs not allowed
var i = Constraint(-22) var i: Constraint<Int> = ConstraintObject(-22, injector)
safetyPlugin.applyCarbsConstraints(i) safetyPlugin.applyCarbsConstraints(i)
assertThat(i.value()).isEqualTo(0) 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 // Apply all limits
i = safetyPlugin.applyCarbsConstraints(Constraint(Constants.REALLYHIGHCARBS)) i = safetyPlugin.applyCarbsConstraints(ConstraintObject(Int.MAX_VALUE, injector))
assertThat(i.value()).isEqualTo(48) 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 @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") `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("teenage")
// Apply all limits // Apply all limits
var d = Constraint(Constants.REALLYHIGHIOB) var d: Constraint<Double> = ConstraintObject(Double.MAX_VALUE, injector)
d = safetyPlugin.applyMaxIOBConstraints(d) d = safetyPlugin.applyMaxIOBConstraints(d)
assertThat(d.value()).isWithin(0.01).of(HardLimits.MAX_IOB_LGS) 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.getReasons()).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.getMostLimitedReasons()).isEqualTo("Safety: Limiting IOB to 0.0 U because of Low Glucose Suspend")
// Apply all limits // Apply all limits
d = Constraint(Constants.REALLYHIGHIOB) d = ConstraintObject(Double.MAX_VALUE, injector)
val a = openAPSAMAPlugin.applyMaxIOBConstraints(d) val a = openAPSAMAPlugin.applyMaxIOBConstraints(d)
assertThat(a.value()).isWithin(0.01).of(1.5) 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.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(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")
// Apply all limits // Apply all limits
d = Constraint(Constants.REALLYHIGHIOB) d = ConstraintObject(Double.MAX_VALUE, injector)
val s = openAPSSMBPlugin.applyMaxIOBConstraints(d) val s = openAPSSMBPlugin.applyMaxIOBConstraints(d)
assertThat(s.value()).isWithin(0.01).of(3.0) 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.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(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

@ -10,11 +10,6 @@ object Constants {
const val MMOLL_TO_MGDL = 18.0 // 18.0182; const val MMOLL_TO_MGDL = 18.0 // 18.0182;
const val MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL const val MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL
const val defaultDIA = 5.0 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 const val notificationID = 556677
// SMS COMMUNICATOR // SMS COMMUNICATOR

View file

@ -1,115 +1,18 @@
package info.nightscout.interfaces.constraints package info.nightscout.interfaces.constraints
import info.nightscout.rx.logging.AAPSLogger interface Constraint<T : Comparable<T>> {
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()
}
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> val reasonList: List<String>
get() = reasons fun getMostLimitedReasons(): String
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()
}
val mostLimitedReasonList: List<String> val mostLimitedReasonList: List<String>
get() = mostLimiting fun copyReasons(another: Constraint<*>)
fun copyReasons(another: Constraint<*>) {
reasons.addAll(another.reasonList)
}
init {
originalValue = value
}
} }

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') implementation project(':core:utils')
testImplementation project(':app-wear-shared:shared-tests') testImplementation project(':app-wear-shared:shared-tests')
testImplementation project(':app-wear-shared:shared-impl')
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 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 android.text.Spanned
import com.google.common.base.Joiner import com.google.common.base.Joiner
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.highValueToUnitsToString import info.nightscout.core.extensions.highValueToUnitsToString
import info.nightscout.core.extensions.lowValueToUnitsToString import info.nightscout.core.extensions.lowValueToUnitsToString
import info.nightscout.core.iob.round 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.Config
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.automation.Automation import info.nightscout.interfaces.automation.Automation
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.db.PersistenceLayer import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.iob.GlucoseStatus import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.GlucoseStatusProvider import info.nightscout.interfaces.iob.GlucoseStatusProvider
@ -63,7 +63,7 @@ class BolusWizard @Inject constructor(
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var profileUtil: ProfileUtil @Inject lateinit var profileUtil: ProfileUtil
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var commandQueue: CommandQueue @Inject lateinit var commandQueue: CommandQueue
@Inject lateinit var loop: Loop @Inject lateinit var loop: Loop
@ -273,7 +273,7 @@ class BolusWizard @Inject constructor(
val bolusStep = activePlugin.activePump.pumpDescription.bolusStep val bolusStep = activePlugin.activePump.pumpDescription.bolusStep
calculatedTotalInsulin = Round.roundTo(calculatedTotalInsulin, bolusStep) calculatedTotalInsulin = Round.roundTo(calculatedTotalInsulin, bolusStep)
insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(calculatedTotalInsulin)).value() insulinAfterConstraints = constraintChecker.applyBolusConstraints(ConstraintObject(calculatedTotalInsulin, injector)).value()
aapsLogger.debug(this.toString()) aapsLogger.debug(this.toString())
return this return this

View file

@ -1,6 +1,8 @@
package info.nightscout.core.data 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 info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -11,41 +13,49 @@ import org.junit.jupiter.api.Test
*/ */
class ConstraintTest : TestBase() { class ConstraintTest : TestBase() {
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
@Test fun doTests() { @Test fun doTests() {
val b = Constraint(true) val b = ConstraintObject(true, injector)
Assertions.assertEquals(true, b.value()) Assertions.assertEquals(true, b.value())
Assertions.assertEquals("", b.getReasons(aapsLogger)) Assertions.assertEquals("", b.getReasons())
Assertions.assertEquals("", b.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("", b.getMostLimitedReasons())
b.set(aapsLogger, false) b.set(false)
Assertions.assertEquals(false, b.value()) Assertions.assertEquals(false, b.value())
Assertions.assertEquals("", b.getReasons(aapsLogger)) Assertions.assertEquals("", b.getReasons())
Assertions.assertEquals("", b.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("", b.getMostLimitedReasons())
b.set(aapsLogger, true, "Set true", this) b.set(true, "Set true", this)
Assertions.assertEquals(true, b.value()) Assertions.assertEquals(true, b.value())
Assertions.assertEquals("ConstraintTest: Set true", b.getReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set true", b.getReasons())
Assertions.assertEquals("ConstraintTest: Set true", b.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set true", b.getMostLimitedReasons())
b.set(aapsLogger, false, "Set false", this) b.set(false, "Set false", this)
Assertions.assertEquals(false, b.value()) 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.getReasons())
Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set true\nConstraintTest: Set false", b.getMostLimitedReasons())
val d = Constraint(10.0) val d = ConstraintObject(10.0, injector)
d.set(aapsLogger, 5.0, "Set 5d", this) d.set(5.0, "Set 5d", this)
Assertions.assertEquals(5.0, d.value(), 0.01) Assertions.assertEquals(5.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d", d.getReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 5d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons())
d.setIfSmaller(aapsLogger, 6.0, "Set 6d", this) d.setIfSmaller(6.0, "Set 6d", this)
Assertions.assertEquals(5.0, d.value(), 0.01) Assertions.assertEquals(5.0, d.value(), 0.01)
Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 5d", d.getMostLimitedReasons())
d.setIfSmaller(aapsLogger, 4.0, "Set 4d", this) d.setIfSmaller(4.0, "Set 4d", this)
Assertions.assertEquals(4.0, d.value(), 0.01) 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 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons())
Assertions.assertEquals(10.0, d.originalValue(), 0.01) 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(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 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getReasons())
Assertions.assertEquals("ConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getMostLimitedReasons(aapsLogger)) Assertions.assertEquals("ConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getMostLimitedReasons())
Assertions.assertEquals(10.0, d.originalValue(), 0.01) 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.core.iob.round
import info.nightscout.interfaces.iob.IobTotal import info.nightscout.interfaces.iob.IobTotal
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -25,7 +26,7 @@ class IobTotalTest : TestBase() {
@BeforeEach @BeforeEach
fun prepare() { fun prepare() {
dateUtil = DateUtil(context) dateUtil = DateUtilImpl(context)
now = dateUtil.now() now = dateUtil.now()
} }

View file

@ -7,11 +7,10 @@ import info.nightscout.core.profile.ProfileSealed
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.utils.HardLimits 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.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.HardLimitsMock import info.nightscout.sharedtests.HardLimitsMock
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import info.nightscout.sharedtests.TestPumpPlugin import info.nightscout.sharedtests.TestPumpPlugin
@ -37,7 +36,6 @@ class ProfileTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
private lateinit var hardLimits: HardLimits private lateinit var hardLimits: HardLimits
private lateinit var rxBus: RxBus
private lateinit var dateUtil: DateUtil private lateinit var dateUtil: DateUtil
private lateinit var testPumpPlugin: TestPumpPlugin private lateinit var testPumpPlugin: TestPumpPlugin
@ -59,8 +57,7 @@ class ProfileTest : TestBase() {
@BeforeEach @BeforeEach
fun prepare() { fun prepare() {
testPumpPlugin = TestPumpPlugin { AndroidInjector { } } testPumpPlugin = TestPumpPlugin { AndroidInjector { } }
dateUtil = DateUtil(context) dateUtil = DateUtilImpl(context)
rxBus = RxBus(TestAapsSchedulers(), aapsLogger)
hardLimits = HardLimitsMock(sp, rh) hardLimits = HardLimitsMock(sp, rh)
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin) `when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
`when`(rh.gs(info.nightscout.core.ui.R.string.profile_per_unit)).thenReturn("/U") `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 android.content.Context
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import info.nightscout.shared.interfaces.ResourceHelper 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.shared.utils.T
import info.nightscout.sharedtests.TestBase 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.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.Mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import java.util.Date import java.util.Date
@ -41,45 +41,45 @@ class DateUtilTest : TestBase() {
@Test @Test
fun fromISODateStringTest() { fun fromISODateStringTest() {
Assertions.assertEquals(1511124634417L, DateUtil(context).fromISODateString("2017-11-19T22:50:34.417+0200")) Assertions.assertEquals(1511124634417L, DateUtilImpl(context).fromISODateString("2017-11-19T22:50:34.417+0200"))
Assertions.assertEquals(1511124634000L, DateUtil(context).fromISODateString("2017-11-19T22:50:34+0200")) Assertions.assertEquals(1511124634000L, DateUtilImpl(context).fromISODateString("2017-11-19T22:50:34+0200"))
Assertions.assertEquals(1512317365000L, DateUtil(context).fromISODateString("2017-12-03T16:09:25.000Z")) Assertions.assertEquals(1512317365000L, DateUtilImpl(context).fromISODateString("2017-12-03T16:09:25.000Z"))
Assertions.assertEquals(1513902750000L, DateUtil(context).fromISODateString("2017-12-22T00:32:30Z")) Assertions.assertEquals(1513902750000L, DateUtilImpl(context).fromISODateString("2017-12-22T00:32:30Z"))
} }
@Test @Test
fun toISOStringTest() { 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() { @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() { @Test fun toSecondsTest() {
Assertions.assertEquals(3600, DateUtil(context).toSeconds("01:00").toLong()) Assertions.assertEquals(3600, DateUtilImpl(context).toSeconds("01:00").toLong())
Assertions.assertEquals(3600, DateUtil(context).toSeconds("01:00 a.m.").toLong()) Assertions.assertEquals(3600, DateUtilImpl(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 AM").toLong())
} }
@Test fun dateStringTest() { @Test fun dateStringTest() {
assertThat(DateUtil(context).dateString(1513902750000L)).contains("22") assertThat(DateUtilImpl(context).dateString(1513902750000L)).contains("22")
} }
@Test fun timeStringTest() { @Test fun timeStringTest() {
Assertions.assertTrue(DateUtil(context).timeString(1513902750000L).contains("32")) Assertions.assertTrue(DateUtilImpl(context).timeString(1513902750000L).contains("32"))
} }
@Test fun dateAndTimeStringTest() { @Test fun dateAndTimeStringTest() {
assertThat(DateUtil(context).dateAndTimeString(1513902750000L)).contains("22") assertThat(DateUtilImpl(context).dateAndTimeString(1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeString(1513902750000L)).contains("32") assertThat(DateUtilImpl(context).dateAndTimeString(1513902750000L)).contains("32")
} }
@Test fun dateAndTimeRangeStringTest() { @Test fun dateAndTimeRangeStringTest() {
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22") assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32") assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22") assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("22")
assertThat(DateUtil(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32") assertThat(DateUtilImpl(context).dateAndTimeRangeString(1513902750000L, 1513902750000L)).contains("32")
} }
/* /*
@ -90,6 +90,6 @@ class DateUtilTest : TestBase() {
*/ */
@Test fun timeFrameStringTest() { @Test fun timeFrameStringTest() {
`when`(rh.gs(info.nightscout.interfaces.R.string.shorthour)).thenReturn("h") `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.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.test.ext:junit-ktx:$androidx_junit_version" androidTestImplementation "androidx.test.ext:junit-ktx:$androidx_junit_version"
androidTestImplementation "androidx.test:rules:$androidx_rules_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' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
} }

View file

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

View file

@ -5,6 +5,7 @@ import android.os.Handler
import android.os.PowerManager import android.os.PowerManager
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.ValueWrapper import info.nightscout.database.ValueWrapper
import info.nightscout.database.entities.Bolus 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.implementation.queue.commands.CommandTempBasalPercent
import info.nightscout.interfaces.AndroidPermission import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.db.PersistenceLayer import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
@ -50,7 +50,7 @@ import java.util.Calendar
class CommandQueueImplementationTest : TestBaseWithProfile() { class CommandQueueImplementationTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var powerManager: PowerManager @Mock lateinit var powerManager: PowerManager
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
@Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var uiInteraction: UiInteraction
@ -63,7 +63,7 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
rxBus: RxBus, rxBus: RxBus,
aapsSchedulers: AapsSchedulers, aapsSchedulers: AapsSchedulers,
rh: ResourceHelper, rh: ResourceHelper,
constraintChecker: Constraints, constraintChecker: ConstraintsChecker,
profileFunction: ProfileFunction, profileFunction: ProfileFunction,
activePlugin: ActivePlugin, activePlugin: ActivePlugin,
context: Context, context: Context,
@ -88,6 +88,9 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
private val injector = HasAndroidInjector { private val injector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is Command) { if (it is Command) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.rh = rh it.rh = rh
@ -140,14 +143,14 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
) )
`when`(profileFunction.getProfile()).thenReturn(validProfile) `when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0) val bolusConstraint = ConstraintObject(0.0, injector)
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint) `when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint)
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(bolusConstraint) `when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(bolusConstraint)
val carbsConstraint = Constraint(0) val carbsConstraint = ConstraintObject(0, injector)
`when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(carbsConstraint) `when`(constraintChecker.applyCarbsConstraints(anyObject())).thenReturn(carbsConstraint)
val rateConstraint = Constraint(0.0) val rateConstraint = ConstraintObject(0.0, injector)
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint) `when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint)
val percentageConstraint = Constraint(0) val percentageConstraint = ConstraintObject(0, injector)
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint) `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.connectiontimedout)).thenReturn("Connection timed out")
`when`(rh.gs(info.nightscout.core.ui.R.string.format_insulin_units)).thenReturn("%1\$.2f U") `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 android.os.PowerManager
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute import info.nightscout.implementation.queue.commands.CommandTempBasalAbsolute
import info.nightscout.interfaces.AndroidPermission import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.db.PersistenceLayer import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.pump.defs.PumpDescription import info.nightscout.interfaces.pump.defs.PumpDescription
@ -25,7 +25,7 @@ import org.mockito.Mockito
class QueueThreadTest : TestBaseWithProfile() { class QueueThreadTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var powerManager: PowerManager @Mock lateinit var powerManager: PowerManager
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
@Mock lateinit var androidPermission: AndroidPermission @Mock lateinit var androidPermission: AndroidPermission
@ -34,6 +34,9 @@ class QueueThreadTest : TestBaseWithProfile() {
private val injector = HasAndroidInjector { private val injector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is Command) { if (it is Command) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.rh = rh it.rh = rh
@ -64,14 +67,14 @@ class QueueThreadTest : TestBaseWithProfile() {
Mockito.`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager) Mockito.`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
Mockito.`when`(profileFunction.getProfile()).thenReturn(validProfile) 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.applyBolusConstraints(anyObject())).thenReturn(bolusConstraint)
Mockito.`when`(constraintChecker.applyExtendedBolusConstraints(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) 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) Mockito.`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(rateConstraint)
val percentageConstraint = Constraint(0) val percentageConstraint = ConstraintObject(0, injector)
Mockito.`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())) Mockito.`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject()))
.thenReturn(percentageConstraint) .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") 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.AutosensDataStore
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint 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.iob.IobTotal
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.pump.defs.PumpDescription import info.nightscout.interfaces.pump.defs.PumpDescription
import info.nightscout.interfaces.queue.CommandQueue import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBaseWithProfile import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mock import org.mockito.Mock
@ -24,7 +23,7 @@ class BolusWizardTest : TestBaseWithProfile() {
private val pumpBolusStep = 0.1 private val pumpBolusStep = 0.1
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue @Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var loop: Loop @Mock lateinit var loop: Loop
@Mock lateinit var autosensDataStore: AutosensDataStore @Mock lateinit var autosensDataStore: AutosensDataStore
@ -34,7 +33,7 @@ class BolusWizardTest : TestBaseWithProfile() {
if (it is BolusWizard) { if (it is BolusWizard) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.rh = rh it.rh = rh
it.rxBus = RxBus(aapsSchedulers, aapsLogger) it.rxBus = rxBus
it.profileFunction = profileFunction it.profileFunction = profileFunction
it.constraintChecker = constraintChecker it.constraintChecker = constraintChecker
it.activePlugin = activePlugin it.activePlugin = activePlugin
@ -113,7 +112,7 @@ class BolusWizardTest : TestBaseWithProfile() {
useAlarm = false useAlarm = false
) )
val bolusForBg54 = bw.calculatedTotalInsulin val bolusForBg54 = bw.calculatedTotalInsulin
assertThat(bolusForBg54).isWithin( 0.01).of(bolusForBg42) assertThat(bolusForBg54).isWithin(0.01).of(bolusForBg42)
} }
@Test @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.core.events.EventNewNotification;
import info.nightscout.interfaces.Config; import info.nightscout.interfaces.Config;
import info.nightscout.interfaces.constraints.Constraint; 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.notifications.Notification;
import info.nightscout.interfaces.plugin.OwnDatabasePlugin; import info.nightscout.interfaces.plugin.OwnDatabasePlugin;
import info.nightscout.interfaces.plugin.PluginDescription; import info.nightscout.interfaces.plugin.PluginDescription;
@ -134,9 +134,10 @@ import info.nightscout.shared.utils.DateUtil;
import info.nightscout.shared.utils.T; import info.nightscout.shared.utils.T;
@Singleton @Singleton
public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight, Constraints, OwnDatabasePlugin, public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight, PluginConstraints, OwnDatabasePlugin,
InsightConnectionService.StateCallback { InsightConnectionService.StateCallback {
public static final String ALERT_CHANNEL_ID = "AAPS-InsightAlert";
private final AAPSLogger aapsLogger; private final AAPSLogger aapsLogger;
private final RxBus rxBus; private final RxBus rxBus;
private final ResourceHelper rh; private final ResourceHelper rh;
@ -148,13 +149,12 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
private final InsightDbHelper insightDbHelper; private final InsightDbHelper insightDbHelper;
private final PumpSync pumpSync; private final PumpSync pumpSync;
private final InsightDatabase insightDatabase; private final InsightDatabase insightDatabase;
public static final String ALERT_CHANNEL_ID = "AAPS-InsightAlert";
private final PumpDescription pumpDescription; private final PumpDescription pumpDescription;
private final Object $bolusLock = new Object[0];
public double lastBolusAmount = 0;
public long lastBolusTimestamp = 0L;
private InsightAlertService alertService; private InsightAlertService alertService;
private InsightConnectionService connectionService; private InsightConnectionService connectionService;
private long timeOffset;
private final ServiceConnection serviceConnection = new ServiceConnection() { private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder binder) { public void onServiceConnected(ComponentName name, IBinder binder) {
@ -174,8 +174,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
connectionService = null; connectionService = null;
} }
}; };
private long timeOffset;
private final Object $bolusLock = new Object[0];
private int bolusID; private int bolusID;
private boolean bolusCancelled; private boolean bolusCancelled;
private BasalProfile activeBasalProfile; private BasalProfile activeBasalProfile;
@ -192,8 +191,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
private List<ActiveBolus> activeBoluses; private List<ActiveBolus> activeBoluses;
private boolean statusLoaded; private boolean statusLoaded;
private TBROverNotificationBlock tbrOverNotificationBlock; private TBROverNotificationBlock tbrOverNotificationBlock;
public double lastBolusAmount = 0;
public long lastBolusTimestamp = 0L;
@Inject @Inject
public LocalInsightPlugin( public LocalInsightPlugin(
@ -1589,22 +1586,22 @@ public class LocalInsightPlugin extends PumpPluginBase implements Pump, Insight,
@NonNull @Override @NonNull @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, @NonNull Profile profile) { 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.setIfGreater(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.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; return percentRate;
} }
@NonNull @Override @NonNull @Override
public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) { public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) {
if (!limitsFetched) return 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) { if (insulin.value() < minimumBolusAmount) {
//TODO: Add function to Constraints or use different approach //TODO: Add function to Constraints or use different approach
// This only works if the interface of the InsightPlugin is called last. // 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 // 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; return insulin;
} }

View file

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

View file

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

View file

@ -14,6 +14,7 @@ import android.os.SystemClock
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.events.EventNewNotification import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.extensions.convertedToAbsolute import info.nightscout.core.extensions.convertedToAbsolute
import info.nightscout.core.extensions.convertedToPercent 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
import info.nightscout.interfaces.aps.Loop.LastRun import info.nightscout.interfaces.aps.Loop.LastRun
import info.nightscout.interfaces.constraints.Constraint 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.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.notifications.Notification
@ -91,7 +92,7 @@ class LoopPlugin @Inject constructor(
private val rxBus: RxBus, private val rxBus: RxBus,
private val sp: SP, private val sp: SP,
private val config: Config, private val config: Config,
private val constraintChecker: Constraints, private val constraintChecker: ConstraintsChecker,
rh: ResourceHelper, rh: ResourceHelper,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val context: Context, private val context: Context,
@ -230,7 +231,7 @@ class LoopPlugin @Inject constructor(
if (!loopEnabled.value()) { if (!loopEnabled.value()) {
val message = """ val message = """
${rh.gs(info.nightscout.core.ui.R.string.loop_disabled)} ${rh.gs(info.nightscout.core.ui.R.string.loop_disabled)}
${loopEnabled.getReasons(aapsLogger)} ${loopEnabled.getReasons()}
""".trimIndent() """.trimIndent()
aapsLogger.debug(LTag.APS, message) aapsLogger.debug(LTag.APS, message)
rxBus.send(EventLoopSetLastRunGui(message)) rxBus.send(EventLoopSetLastRunGui(message))
@ -274,11 +275,11 @@ class LoopPlugin @Inject constructor(
// check rate for constraints // check rate for constraints
val resultAfterConstraints = apsResult.newAndClone(injector) 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.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.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() resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint!!).value()
// safety check for multiple SMBs // 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.GlucoseUnit
import info.nightscout.interfaces.aps.DetermineBasalAdapter import info.nightscout.interfaces.aps.DetermineBasalAdapter
import info.nightscout.interfaces.aps.SMBDefaults import info.nightscout.interfaces.aps.SMBDefaults
import info.nightscout.interfaces.constraints.Constraints import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.iob.GlucoseStatus import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.iob.IobTotal import info.nightscout.interfaces.iob.IobTotal
@ -43,7 +43,7 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
private val injector: HasAndroidInjector private val injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@ -107,7 +107,8 @@ class DetermineBasalAdapterAMAJS internal constructor(scriptReader: ScriptReader
makeParam(profile, rhino, scope), makeParam(profile, rhino, scope),
makeParam(autosensData, rhino, scope), makeParam(autosensData, rhino, scope),
makeParam(mealData, rhino, scope), makeParam(mealData, rhino, scope),
setTempBasalFunctionsObj) setTempBasalFunctionsObj
)
val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject val jsResult = determineBasalObj.call(rhino, scope, scope, params) as NativeObject
scriptDebug = LoggerCallback.scriptDebug scriptDebug = LoggerCallback.scriptDebug

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,6 +26,7 @@ dependencies {
implementation project(':database:impl') implementation project(':database:impl')
testImplementation project(':app-wear-shared:shared-tests') testImplementation project(':app-wear-shared:shared-tests')
testImplementation project(':app-wear-shared:shared-impl')
testImplementation project(':implementation') testImplementation project(':implementation')
testImplementation project(':plugins:main') 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.aps.Loop
import info.nightscout.interfaces.automation.Automation import info.nightscout.interfaces.automation.Automation
import info.nightscout.interfaces.automation.AutomationEvent 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.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
@ -87,7 +87,7 @@ class AutomationPlugin @Inject constructor(
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val loop: Loop, private val loop: Loop,
private val rxBus: RxBus, private val rxBus: RxBus,
private val constraintChecker: Constraints, private val constraintChecker: ConstraintsChecker,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers, private val aapsSchedulers: AapsSchedulers,
private val config: Config, private val config: Config,
@ -244,7 +244,7 @@ class AutomationPlugin @Inject constructor(
} }
val enabled = constraintChecker.isAutomationEnabled() val enabled = constraintChecker.isAutomationEnabled()
if (!enabled.value()) { if (!enabled.value()) {
executionLog.add(enabled.getMostLimitedReasons(aapsLogger)) executionLog.add(enabled.getMostLimitedReasons())
rxBus.send(EventAutomationUpdateGui()) rxBus.send(EventAutomationUpdateGui())
commonEventsEnabled = false 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 * @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.automation.triggers.TriggerDummy
import info.nightscout.interfaces.ConfigBuilder import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import org.json.JSONObject import org.json.JSONObject
@ -36,7 +35,7 @@ class AutomationEventTest : TestBase() {
it.loopPlugin = loopPlugin it.loopPlugin = loopPlugin
it.rh = rh it.rh = rh
it.configBuilder = configBuilder 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.Config
import info.nightscout.interfaces.GlucoseUnit import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop 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.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -32,8 +32,7 @@ class BolusTimerImplTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var loop: Loop @Mock lateinit var loop: Loop
@Mock lateinit var rxBus: RxBus @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var constraintChecker: Constraints
@Mock lateinit var config: Config @Mock lateinit var config: Config
@Mock lateinit var locationServiceHelper: LocationServiceHelper @Mock lateinit var locationServiceHelper: LocationServiceHelper
@Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var activePlugin: ActivePlugin
@ -49,16 +48,17 @@ class BolusTimerImplTest : TestBase() {
} }
} }
private lateinit var dateUtil: DateUtil private lateinit var dateUtil: DateUtil
private lateinit var automationPlugin: AutomationPlugin private lateinit var automationPlugin: AutomationPlugin
@BeforeEach @BeforeEach
fun init() { fun init() {
Mockito.`when`(rh.gs(anyInt())).thenReturn("") Mockito.`when`(rh.gs(anyInt())).thenReturn("")
Mockito.`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL) Mockito.`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
dateUtil = DateUtil(context) dateUtil = DateUtilImpl(context)
automationPlugin = AutomationPlugin(injector, rh, context, sp, fabricPrivacy, loop, rxBus, constraintChecker, aapsLogger, aapsSchedulers, config, locationServiceHelper, dateUtil, automationPlugin = AutomationPlugin(
activePlugin, timerUtil) injector, rh, context, sp, fabricPrivacy, loop, rxBus, constraintChecker, aapsLogger, aapsSchedulers, config, locationServiceHelper, dateUtil,
activePlugin, timerUtil
)
} }
@Test @Test

View file

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

View file

@ -26,7 +26,7 @@ class ActionNotificationTest : TestBase() {
@Mock lateinit var rh: ResourceHelper @Mock lateinit var rh: ResourceHelper
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var rxBus: RxBus @Mock lateinit var rxBusMocked: RxBus
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
private lateinit var sut: ActionNotification private lateinit var sut: ActionNotification
@ -34,7 +34,7 @@ class ActionNotificationTest : TestBase() {
AndroidInjector { AndroidInjector {
if (it is ActionNotification) { if (it is ActionNotification) {
it.rh = rh it.rh = rh
it.rxBus = rxBus it.rxBus = rxBusMocked
it.repository = repository it.repository = repository
} }
if (it is PumpEnactResult) { if (it is PumpEnactResult) {
@ -78,7 +78,7 @@ class ActionNotificationTest : TestBase() {
Assertions.assertTrue(result.success) 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)) //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.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.automation.triggers.Trigger 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.entities.OfflineEvent
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.ConfigBuilder import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.GlucoseUnit import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profile.ProfileSource import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.queue.CommandQueue import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.interfaces.smsCommunicator.SmsCommunicator import info.nightscout.interfaces.smsCommunicator.SmsCommunicator
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil
import info.nightscout.sharedtests.TestBaseWithProfile import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock import org.mockito.Mock
@ -45,7 +40,7 @@ ActionsTestBase : TestBaseWithProfile() {
private var suspended = false private var suspended = false
override var lastRun: Loop.LastRun? = Loop.LastRun() 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 isSuspended: Boolean = suspended
override val isLGS: Boolean = false override val isLGS: Boolean = false
override val isSuperBolus: Boolean = false override val isSuperBolus: Boolean = false
@ -174,6 +169,9 @@ ActionsTestBase : TestBaseWithProfile() {
it.rh = rh it.rh = rh
it.aapsLogger = aapsLogger 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.implementation.iob.GlucoseStatusProviderImpl
import info.nightscout.interfaces.aps.AutosensDataStore import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBaseWithProfile import info.nightscout.sharedtests.TestBaseWithProfile
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.mockito.Mock import org.mockito.Mock
@ -31,7 +30,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
AndroidInjector { AndroidInjector {
if (it is Trigger) { if (it is Trigger) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.rxBus = RxBus(aapsSchedulers, aapsLogger) it.rxBus = rxBus
it.rh = rh it.rh = rh
it.profileFunction = profileFunction it.profileFunction = profileFunction
it.sp = sp it.sp = sp

View file

@ -1,109 +1,135 @@
package info.nightscout.plugins.constraints 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.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.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@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> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isLoopInvocationAllowed(value) constraint.isLoopInvocationAllowed(value)
} }
return value return value
} }
override fun isClosedLoopAllowed(): Constraint<Boolean> = isClosedLoopAllowed(ConstraintObject(true, injector))
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isClosedLoopAllowed(value) constraint.isClosedLoopAllowed(value)
} }
return value return value
} }
override fun isLgsAllowed(): Constraint<Boolean> = isLgsAllowed(ConstraintObject(true, injector))
override fun isLgsAllowed(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isLgsAllowed(value) constraint.isLgsAllowed(value)
} }
return value return value
} }
override fun isAutosensModeEnabled(): Constraint<Boolean> = isAutosensModeEnabled(ConstraintObject(true, injector))
override fun isAutosensModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isAutosensModeEnabled(value) constraint.isAutosensModeEnabled(value)
} }
return value return value
} }
override fun isSMBModeEnabled(): Constraint<Boolean> = isSMBModeEnabled(ConstraintObject(true, injector))
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isSMBModeEnabled(value) constraint.isSMBModeEnabled(value)
} }
return value return value
} }
override fun isDynIsfModeEnabled(): Constraint<Boolean> = isDynIsfModeEnabled(ConstraintObject(true, injector))
override fun isDynIsfModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isDynIsfModeEnabled(value) constraint.isDynIsfModeEnabled(value)
} }
return value return value
} }
override fun isUAMEnabled(): Constraint<Boolean> = isUAMEnabled(ConstraintObject(true, injector))
override fun isUAMEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isUAMEnabled(value) constraint.isUAMEnabled(value)
} }
return value return value
} }
override fun isAdvancedFilteringEnabled(): Constraint<Boolean> = isAdvancedFilteringEnabled(ConstraintObject(true, injector))
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isAdvancedFilteringEnabled(value) constraint.isAdvancedFilteringEnabled(value)
} }
return value return value
} }
override fun isSuperBolusEnabled(): Constraint<Boolean> = isSuperBolusEnabled(ConstraintObject(true, injector))
override fun isSuperBolusEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isSuperBolusEnabled(value) constraint.isSuperBolusEnabled(value)
} }
return value return value
} }
override fun isAutomationEnabled(): Constraint<Boolean> = isAutomationEnabled(ConstraintObject(true, injector))
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.applyBasalConstraints(absoluteRate, profile) 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> { 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) { for (p in constraintsPlugins) {
val constrain = p as Constraints val constrain = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constrain.applyBasalPercentConstraints(percentRate, profile) constrain.applyBasalPercentConstraints(percentRate, profile)
} }
@ -121,9 +147,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
} }
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> { 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) { for (p in constraintsPlugins) {
val constrain = p as Constraints val constrain = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constrain.applyBolusConstraints(insulin) constrain.applyBolusConstraints(insulin)
} }
@ -131,9 +157,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
} }
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> { 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) { for (p in constraintsPlugins) {
val constrain = p as Constraints val constrain = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constrain.applyExtendedBolusConstraints(insulin) constrain.applyExtendedBolusConstraints(insulin)
} }
@ -141,9 +167,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
} }
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> { 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) { for (p in constraintsPlugins) {
val constrain = p as Constraints val constrain = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constrain.applyCarbsConstraints(carbs) constrain.applyCarbsConstraints(carbs)
} }
@ -151,9 +177,9 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
} }
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> { 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) { for (p in constraintsPlugins) {
val constrain = p as Constraints val constrain = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constrain.applyMaxIOBConstraints(maxIob) constrain.applyMaxIOBConstraints(maxIob)
} }
@ -161,12 +187,34 @@ class ConstraintsImpl @Inject constructor(private val activePlugin: ActivePlugin
} }
override fun isAutomationEnabled(value: Constraint<Boolean>): Constraint<Boolean> { 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) { for (p in constraintsPlugins) {
val constraint = p as Constraints val constraint = p as PluginConstraints
if (!p.isEnabled()) continue if (!p.isEnabled()) continue
constraint.isAutomationEnabled(value) constraint.isAutomationEnabled(value)
} }
return 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.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Constraints import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
@ -48,7 +48,7 @@ class BgQualityCheckPlugin @Inject constructor(
.showInList(false) .showInList(false)
.pluginName(R.string.bg_quality), .pluginName(R.string.bg_quality),
aapsLogger, rh, injector aapsLogger, rh, injector
), Constraints, BgQualityCheck { ), PluginConstraints, BgQualityCheck {
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
@ -71,7 +71,7 @@ class BgQualityCheckPlugin @Inject constructor(
// Fallback to LGS if BG values are doubled // Fallback to LGS if BG values are doubled
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> = override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (state == BgQualityCheck.State.DOUBLED) 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 else
maxIob maxIob

View file

@ -3,9 +3,9 @@ package info.nightscout.plugins.constraints.di
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck 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.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.bgQualityCheck.BgQualityCheckPlugin
import info.nightscout.plugins.constraints.versionChecker.VersionCheckerUtilsImpl import info.nightscout.plugins.constraints.versionChecker.VersionCheckerUtilsImpl
@ -24,6 +24,6 @@ abstract class PluginsConstraintsModule {
@Binds fun bindVersionCheckerUtils(versionCheckerUtils: VersionCheckerUtilsImpl): VersionCheckerUtils @Binds fun bindVersionCheckerUtils(versionCheckerUtils: VersionCheckerUtilsImpl): VersionCheckerUtils
@Binds fun bindBgQualityCheck(bgQualityCheck: BgQualityCheckPlugin): BgQualityCheck @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 dagger.android.HasAndroidInjector
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint 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.notifications.Notification
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
@ -35,7 +35,7 @@ class DstHelperPlugin @Inject constructor(
.showInList(false) .showInList(false)
.pluginName(R.string.dst_plugin_name), .pluginName(R.string.dst_plugin_name),
aapsLogger, rh, injector aapsLogger, rh, injector
), Constraints { ), PluginConstraints {
companion object { companion object {
@ -74,7 +74,7 @@ class DstHelperPlugin @Inject constructor(
} else { } else {
aapsLogger.debug(LTag.CONSTRAINTS, "Loop already suspended") 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 return value
} }

View file

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

View file

@ -1,9 +1,8 @@
package info.nightscout.plugins.constraints.objectives.objectives package info.nightscout.plugins.constraints.objectives.objectives
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Constants import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.plugins.constraints.R 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 profileFunction: ProfileFunction
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
init { init {
tasks.add( tasks.add(
object : Task(this, R.string.objectives_maxbasal_gate) { object : Task(this, R.string.objectives_maxbasal_gate) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
val profile = profileFunction.getProfile() ?: return false 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() val maxDailyBasal = profile.getMaxDailyBasal()
return maxBasalSet.value() > 2.8 * maxDailyBasal return maxBasalSet.value() > 2.8 * maxDailyBasal
} }

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
package info.nightscout.plugins.constraints.safety package info.nightscout.plugins.constraints.safety
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.extensions.putDouble import info.nightscout.core.utils.extensions.putDouble
import info.nightscout.core.utils.extensions.putInt import info.nightscout.core.utils.extensions.putInt
import info.nightscout.core.utils.extensions.putString 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.ApsMode
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint 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.constraints.Safety
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.notifications.Notification
@ -39,7 +41,7 @@ class SafetyPlugin @Inject constructor(
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
rh: ResourceHelper, rh: ResourceHelper,
private val sp: SP, private val sp: SP,
private val constraintChecker: Constraints, private val constraintChecker: ConstraintsChecker,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val hardLimits: HardLimits, private val hardLimits: HardLimits,
private val config: Config, private val config: Config,
@ -56,57 +58,57 @@ class SafetyPlugin @Inject constructor(
.pluginName(R.string.safety) .pluginName(R.string.safety)
.preferencesId(R.xml.pref_safety), .preferencesId(R.xml.pref_safety),
aapsLogger, rh, injector aapsLogger, rh, injector
), Constraints, Safety { ), PluginConstraints, Safety {
/** /**
* Constraints interface * Constraints interface
*/ */
override fun isLoopInvocationAllowed(value: Constraint<Boolean>): Constraint<Boolean> { 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 return value
} }
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> { 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)) 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 (!config.isEngineeringModeOrRelease()) {
if (value.value()) { if (value.value()) {
uiInteraction.addNotification(Notification.TOAST_ALARM, rh.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL) 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 val pump = activePlugin.activePump
if (!pump.isFakingTempsByExtendedBoluses && iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) { 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 return value
} }
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> { override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val closedLoop = constraintChecker.isClosedLoopAllowed() 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 return value
} }
override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> { override fun isAdvancedFilteringEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val bgSource = activePlugin.activeBgSource 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 return value
} }
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> { 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.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(aapsLogger, hardLimits.maxBasal(), rh.gs(info.nightscout.core.ui.R.string.limitingbasalratio, hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), 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 val pump = activePlugin.activePump
// check for pump max // check for pump max
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 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 // do rounding
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) { 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 return absoluteRate
} }
@ -119,52 +121,58 @@ class SafetyPlugin @Inject constructor(
currentBasal currentBasal
) + " U/h", this ) + " U/h", this
) )
val absoluteConstraint = Constraint(absoluteRate) val absoluteConstraint = ConstraintObject(absoluteRate, injector)
applyBasalConstraints(absoluteConstraint, profile) applyBasalConstraints(absoluteConstraint, profile)
percentRate.copyReasons(absoluteConstraint) percentRate.copyReasons(absoluteConstraint)
val pump = activePlugin.activePump val pump = activePlugin.activePump
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt() 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() percentRateAfterConst =
percentRate.set(aapsLogger, percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.limitingpercentrate, percentRateAfterConst, rh.gs(info.nightscout.core.ui.R.string.pumplimit)), this) 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) { if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0 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 return percentRate
} }
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> { 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) 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(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(hardLimits.maxBolus(), rh.gs(info.nightscout.core.ui.R.string.limitingbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value()) 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 return insulin
} }
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> { 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) 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(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(hardLimits.maxBolus(), rh.gs(R.string.limitingextendedbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
val pump = activePlugin.activePump val pump = activePlugin.activePump
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value()) 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 return insulin
} }
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> { 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) 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 return carbs
} }
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> { 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)) 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 return maxIob
} }

View file

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

View file

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

View file

@ -3,7 +3,7 @@ package info.nightscout.plugins.constraints.versionChecker
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint 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.notifications.Notification
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
@ -40,7 +40,7 @@ class VersionCheckerPlugin @Inject constructor(
.showInList(false) .showInList(false)
.pluginName(R.string.version_checker), .pluginName(R.string.version_checker),
aapsLogger, rh, injector aapsLogger, rh, injector
), Constraints { ), PluginConstraints {
enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) { enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) {
RELEASE(30, 60, 90), RELEASE(30, 60, 90),
@ -64,16 +64,16 @@ class VersionCheckerPlugin @Inject constructor(
checkWarning() checkWarning()
versionCheckerUtils.triggerCheckVersion() versionCheckerUtils.triggerCheckVersion()
if (lastCheckOlderThan(gracePeriod.veryOld.daysToMillis())) 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) 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) 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 return value
} }
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> = override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (lastCheckOlderThan(gracePeriod.old.daysToMillis())) 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 else
maxIob maxIob

View file

@ -2,16 +2,15 @@ package info.nightscout.plugins.constraints.bgQualityCheck
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.entities.GlucoseValue import info.nightscout.database.entities.GlucoseValue
import info.nightscout.interfaces.aps.AutosensDataStore import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.iob.InMemoryGlucoseValue import info.nightscout.interfaces.iob.InMemoryGlucoseValue
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.constraints.R import info.nightscout.plugins.constraints.R
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
@ -35,7 +34,13 @@ class BgQualityCheckPluginTest : TestBase() {
private lateinit var plugin: BgQualityCheckPlugin 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 now = 100000000L
//private val autosensDataStore = AutosensDataStoreObject() //private val autosensDataStore = AutosensDataStoreObject()
@ -46,7 +51,7 @@ class BgQualityCheckPluginTest : TestBase() {
injector, injector,
aapsLogger, aapsLogger,
rh, rh,
RxBus(aapsSchedulers, aapsLogger), rxBus,
iobCobCalculator, iobCobCalculator,
aapsSchedulers, aapsSchedulers,
fabricPrivacy, fabricPrivacy,
@ -75,10 +80,46 @@ class BgQualityCheckPluginTest : TestBase() {
Assertions.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon()) Assertions.assertEquals(R.drawable.ic_baseline_warning_24_yellow, plugin.icon())
val superData: MutableList<GlucoseValue> = ArrayList() val superData: MutableList<GlucoseValue> = ArrayList()
superData.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER, trendArrow = GlucoseValue.TrendArrow.FLAT)) superData.add(
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)) GlucoseValue(
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)) raw = 0.0,
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)) 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.getBgReadingsDataTableCopy()).thenReturn(superData)
`when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true) `when`(autosensDataStore.lastUsed5minCalculation).thenReturn(true)
@ -205,16 +246,106 @@ class BgQualityCheckPluginTest : TestBase() {
// Flat data Libre // Flat data Libre
val flatData: MutableList<GlucoseValue> = ArrayList() 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(
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)) GlucoseValue(
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)) raw = 0.0,
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)) noise = 0.0,
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)) value = 100.0,
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)) timestamp = now + T.mins(0).msecs(),
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)) sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_OTHER,
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)) 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(-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`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(flatData)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatData[0])) `when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatData[0]))
@ -224,16 +355,106 @@ class BgQualityCheckPluginTest : TestBase() {
// Flat data Libre // Flat data Libre
val flatDataDexcom: MutableList<GlucoseValue> = ArrayList() 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(
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)) GlucoseValue(
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)) raw = 0.0,
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)) noise = 0.0,
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)) value = 100.0,
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)) timestamp = now + T.mins(0).msecs(),
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)) sourceSensor = GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
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)) 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(-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`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(flatDataDexcom)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatDataDexcom[0])) `when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(flatDataDexcom[0]))
@ -243,19 +464,100 @@ class BgQualityCheckPluginTest : TestBase() {
// not enough data // not enough data
val incompleteData: MutableList<GlucoseValue> = ArrayList() 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(
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)) 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`(autosensDataStore.getBgReadingsDataTableCopy()).thenReturn(incompleteData)
`when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(incompleteData[0])) `when`(iobCobCalculator.ads.lastBg()).thenReturn(InMemoryGlucoseValue(incompleteData[0]))
plugin.processBgData()// must be more than 5 values plugin.processBgData()// must be more than 5 values
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state) 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(
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)) GlucoseValue(
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)) raw = 0.0,
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)) noise = 0.0,
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)) value = 101.0,
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)) timestamp = now + T.mins(-10).msecs(),
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)) 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 plugin.processBgData() // must be at least 45 min old
Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state) Assertions.assertNotEquals(BgQualityCheck.State.FLAT, plugin.state)
} }
@ -263,13 +565,13 @@ class BgQualityCheckPluginTest : TestBase() {
@Test @Test
fun applyMaxIOBConstraintsTest() { fun applyMaxIOBConstraintsTest() {
plugin.state = BgQualityCheck.State.UNKNOWN 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 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 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 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.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.Objectives import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.constraints.R import info.nightscout.plugins.constraints.R
@ -35,6 +35,9 @@ class ObjectivesPluginTest : TestBase() {
it.rh = rh it.rh = rh
it.dateUtil = dateUtil it.dateUtil = dateUtil
} }
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
} }
} }
@ -49,34 +52,30 @@ class ObjectivesPluginTest : TestBase() {
@Test fun notStartedObjectivesShouldLimitLoopInvocation() { @Test fun notStartedObjectivesShouldLimitLoopInvocation() {
objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = 0 objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = 0
var c = Constraint(true) val c = objectivesPlugin.isLoopInvocationAllowed(ConstraintObject(true, injector))
c = objectivesPlugin.isLoopInvocationAllowed(c) Assertions.assertEquals("Objectives: Objective 1 not started", c.getReasons())
Assertions.assertEquals("Objectives: Objective 1 not started", c.getReasons(aapsLogger))
Assertions.assertEquals(false, c.value()) Assertions.assertEquals(false, c.value())
objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = dateUtil.now() objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].startedOn = dateUtil.now()
} }
@Test fun notStartedObjective6ShouldLimitClosedLoop() { @Test fun notStartedObjective6ShouldLimitClosedLoop() {
objectivesPlugin.objectives[Objectives.MAXIOB_ZERO_CL_OBJECTIVE].startedOn = 0 objectivesPlugin.objectives[Objectives.MAXIOB_ZERO_CL_OBJECTIVE].startedOn = 0
var c = Constraint(true) val c = objectivesPlugin.isClosedLoopAllowed(ConstraintObject(true, injector))
c = objectivesPlugin.isClosedLoopAllowed(c) Assertions.assertEquals(true, c.getReasons().contains("Objective 6 not started"))
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 6 not started"))
Assertions.assertEquals(false, c.value()) Assertions.assertEquals(false, c.value())
} }
@Test fun notStartedObjective8ShouldLimitAutosensMode() { @Test fun notStartedObjective8ShouldLimitAutosensMode() {
objectivesPlugin.objectives[Objectives.AUTOSENS_OBJECTIVE].startedOn = 0 objectivesPlugin.objectives[Objectives.AUTOSENS_OBJECTIVE].startedOn = 0
var c = Constraint(true) val c = objectivesPlugin.isAutosensModeEnabled(ConstraintObject(true, injector))
c = objectivesPlugin.isAutosensModeEnabled(c) Assertions.assertEquals(true, c.getReasons().contains("Objective 8 not started"))
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 8 not started"))
Assertions.assertEquals(false, c.value()) Assertions.assertEquals(false, c.value())
} }
@Test fun notStartedObjective10ShouldLimitSMBMode() { @Test fun notStartedObjective10ShouldLimitSMBMode() {
objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0 objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0
var c = Constraint(true) val c = objectivesPlugin.isSMBModeEnabled(ConstraintObject(true, injector))
c = objectivesPlugin.isSMBModeEnabled(c) Assertions.assertEquals(true, c.getReasons().contains("Objective 9 not started"))
Assertions.assertEquals(true, c.getReasons(aapsLogger).contains("Objective 9 not started"))
Assertions.assertEquals(false, c.value()) Assertions.assertEquals(false, c.value())
} }
} }

View file

@ -2,7 +2,7 @@ package info.nightscout.plugins.constraints.storage
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector 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.interfaces.ui.UiInteraction
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
@ -20,6 +20,13 @@ class StorageConstraintPluginTest : TestBase() {
@Mock lateinit var rh: ResourceHelper @Mock lateinit var rh: ResourceHelper
@Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var uiInteraction: UiInteraction
private val injector = HasAndroidInjector {
AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
}
private lateinit var storageConstraintPlugin: StorageConstraintPlugin private lateinit var storageConstraintPlugin: StorageConstraintPlugin
@BeforeEach fun prepareMock() { @BeforeEach fun prepareMock() {
@ -42,9 +49,9 @@ class StorageConstraintPluginTest : TestBase() {
val mocked = MockedStorageConstraintPlugin({ AndroidInjector { } }, aapsLogger, rh, uiInteraction) val mocked = MockedStorageConstraintPlugin({ AndroidInjector { } }, aapsLogger, rh, uiInteraction)
// Set free space under 200(Mb) to disable loop // Set free space under 200(Mb) to disable loop
mocked.memSize = 150L 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 // Set free space over 200(Mb) to enable loop
mocked.memSize = 300L 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.profile.ProfileFunction
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HardLimits import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.rx.bus.RxBus
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
@ -29,7 +28,6 @@ class InsulinOrefFreePeakPluginTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var rh: ResourceHelper @Mock lateinit var rh: ResourceHelper
@Mock lateinit var rxBus: RxBus
@Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var config: Config @Mock lateinit var config: Config
@Mock lateinit var hardLimits: HardLimits @Mock lateinit var hardLimits: HardLimits

View file

@ -27,6 +27,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.extensions.directionToIcon import info.nightscout.core.extensions.directionToIcon
import info.nightscout.core.graph.OverviewData import info.nightscout.core.graph.OverviewData
import info.nightscout.core.iob.displayText 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.aps.VariableSensitivityResult
import info.nightscout.interfaces.automation.Automation import info.nightscout.interfaces.automation.Automation
import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.iob.GlucoseStatusProvider import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
@ -121,7 +121,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var defaultValueHelper: DefaultValueHelper @Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var profileUtil: ProfileUtil @Inject lateinit var profileUtil: ProfileUtil
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var statusLightHandler: StatusLightHandler @Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var processedDeviceStatusData: ProcessedDeviceStatusData @Inject lateinit var processedDeviceStatusData: ProcessedDeviceStatusData
@Inject lateinit var nsSettingsStatus: NSSettingsStatus @Inject lateinit var nsSettingsStatus: NSSettingsStatus
@ -516,7 +516,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg) val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg)
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) { 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 { activity?.let {
if (abs(wizard.insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(wizard.insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) { 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)) 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 androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.annotations.OpenForTesting import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.events.EventNewNotification import info.nightscout.core.events.EventNewNotification
import info.nightscout.core.iob.generateCOBString import info.nightscout.core.iob.generateCOBString
import info.nightscout.core.iob.round import info.nightscout.core.iob.round
@ -34,8 +35,7 @@ import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.XDripBroadcast import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.iob.GlucoseStatusProvider import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
@ -91,7 +91,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private val smsManager: SmsManager?, private val smsManager: SmsManager?,
private val aapsSchedulers: AapsSchedulers, private val aapsSchedulers: AapsSchedulers,
private val sp: SP, private val sp: SP,
private val constraintChecker: Constraints, private val constraintChecker: ConstraintsChecker,
private val rxBus: RxBus, private val rxBus: RxBus,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val profileUtil: ProfileUtil, 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 (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 if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.sms_wrong_tbr_duration, durationStep)))
else { else {
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value() tempBasalPct = constraintChecker.applyBasalPercentConstraints(ConstraintObject(tempBasalPct, injector), profile).value()
val passCode = generatePassCode() val passCode = generatePassCode()
val reply = rh.gs(R.string.smscommunicator_basal_pct_reply_with_code, tempBasalPct, duration, passCode) val reply = rh.gs(R.string.smscommunicator_basal_pct_reply_with_code, tempBasalPct, duration, passCode)
receivedSms.processed = true 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 (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 if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.sms_wrong_tbr_duration, durationStep)))
else { else {
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value() tempBasal = constraintChecker.applyBasalConstraints(ConstraintObject(tempBasal, injector), profile).value()
val passCode = generatePassCode() val passCode = generatePassCode()
val reply = rh.gs(R.string.smscommunicator_basal_reply_with_code, tempBasal, duration, passCode) val reply = rh.gs(R.string.smscommunicator_basal_reply_with_code, tempBasal, duration, passCode)
receivedSms.processed = true receivedSms.processed = true
@ -864,7 +864,7 @@ class SmsCommunicatorPlugin @Inject constructor(
} else { } else {
var extended = SafeParse.stringToDouble(divided[1]) var extended = SafeParse.stringToDouble(divided[1])
val duration = SafeParse.stringToInt(divided[2]) 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))) if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else { else {
val passCode = generatePassCode() val passCode = generatePassCode()
@ -918,7 +918,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processBOLUS(divided: Array<String>, receivedSms: Sms) { private fun processBOLUS(divided: Array<String>, receivedSms: Sms) {
var bolus = SafeParse.stringToDouble(divided[1]) var bolus = SafeParse.stringToDouble(divided[1])
val isMeal = divided.size > 2 && divided[2].equals("MEAL", ignoreCase = true) 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) { if (divided.size == 3 && !isMeal) {
sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format))) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
} else if (bolus > 0.0) { } else if (bolus > 0.0) {
@ -1031,7 +1031,7 @@ class SmsCommunicatorPlugin @Inject constructor(
return 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))) if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format)))
else { else {
val passCode = generatePassCode() val passCode = generatePassCode()

View file

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

View file

@ -4,6 +4,7 @@ import android.telephony.SmsManager
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.database.entities.GlucoseValue import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.transactions.CancelCurrentOfflineEventIfAnyTransaction 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.XDripBroadcast
import info.nightscout.interfaces.aps.AutosensDataStore import info.nightscout.interfaces.aps.AutosensDataStore
import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.iob.CobInfo import info.nightscout.interfaces.iob.CobInfo
import info.nightscout.interfaces.iob.InMemoryGlucoseValue import info.nightscout.interfaces.iob.InMemoryGlucoseValue
import info.nightscout.interfaces.iob.IobTotal import info.nightscout.interfaces.iob.IobTotal
@ -48,7 +48,7 @@ import org.mockito.invocation.InvocationOnMock
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
class SmsCommunicatorPluginTest : TestBaseWithProfile() { class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue @Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var loop: Loop @Mock lateinit var loop: Loop
@Mock lateinit var profileSource: ProfileSource @Mock lateinit var profileSource: ProfileSource
@ -62,6 +62,9 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
private var injector: HasAndroidInjector = HasAndroidInjector { private var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
if (it is PumpEnactResult) { if (it is PumpEnactResult) {
it.context = context it.context = context
} }
@ -836,7 +839,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 20% 20") 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.") 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 //BASAL 20% 30
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -862,7 +865,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 1 0") 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.") 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 //BASAL 1 20
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -870,7 +873,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BASAL 1 20") 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.") 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 //BASAL 1 30
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -918,7 +921,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("EXTENDED a%") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("EXTENDED a%")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format") 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 //EXTENDED 1 0
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -955,7 +958,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format") 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`(dateUtilMocked.now()).thenReturn(1000L)
`when`(sp.getLong(R.string.key_smscommunicator_remote_bolus_min_distance, T.msecs(Constants.remoteBolusMinDistance).mins())).thenReturn(15L) `when`(sp.getLong(R.string.key_smscommunicator_remote_bolus_min_distance, T.msecs(Constants.remoteBolusMinDistance).mins())).thenReturn(15L)
//BOLUS 1 //BOLUS 1
@ -964,7 +967,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS 1") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS 1")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Remote bolus not available. Try again later.") 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) `when`(dateUtilMocked.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L)
//BOLUS 0 //BOLUS 0
@ -980,8 +983,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS a") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("BOLUS a")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format") 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))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0)) `when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(1.0, injector))
//BOLUS 1 //BOLUS 1
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -1078,7 +1081,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format") 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 //CARBS 0
smsCommunicatorPlugin.messages = ArrayList() smsCommunicatorPlugin.messages = ArrayList()
@ -1086,7 +1089,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms) smsCommunicatorPlugin.processSms(sms)
assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS 0") assertThat(smsCommunicatorPlugin.messages[0].text).isEqualTo("CARBS 0")
assertThat(smsCommunicatorPlugin.messages[1].text).isEqualTo("Wrong format") 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 //CARBS 1
smsCommunicatorPlugin.messages = ArrayList() 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.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.DateUtilImpl
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
@ -46,7 +47,7 @@ class AutosensDataStoreTest : TestBase() {
@BeforeEach @BeforeEach
fun mock() { fun mock() {
dateUtil = DateUtil(context) dateUtil = DateUtilImpl(context)
} }
@Test @Test

View file

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

View file

@ -3,7 +3,6 @@ package info.nightscout.plugins.sync.nsclient
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventChargingState import info.nightscout.rx.events.EventChargingState
import info.nightscout.rx.events.EventNetworkChange import info.nightscout.rx.events.EventNetworkChange
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
@ -20,7 +19,6 @@ class ReceiverDelegateTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var rh: ResourceHelper @Mock lateinit var rh: ResourceHelper
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
private val rxBus = RxBus(aapsSchedulers, aapsLogger)
@Mock private lateinit var receiverStatusStore: ReceiverStatusStore @Mock private lateinit var receiverStatusStore: ReceiverStatusStore
private lateinit var sut: ReceiverDelegate 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.interfaces.sync.NsClient
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3 import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.sharedtests.TestBase import info.nightscout.sharedtests.TestBase
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -30,7 +29,6 @@ internal class DataSyncWorkerTest : TestBase() {
@Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3 @Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
@Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var nsClient: NsClient @Mock lateinit var nsClient: NsClient
@Mock lateinit var rxBus: RxBus
@Mock lateinit var nsClientV3Plugin: NSClientV3Plugin @Mock lateinit var nsClientV3Plugin: NSClientV3Plugin
@Mock lateinit var context: ContextWithInjector @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.DataSyncSelectorV3
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3 import info.nightscout.plugins.sync.nsclientV3.extensions.toNSSvgV3
import info.nightscout.rx.bus.RxBus
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.remotemodel.LastModified import info.nightscout.sdk.remotemodel.LastModified
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
@ -66,7 +65,6 @@ internal class LoadBgWorkerTest : TestBase() {
@Mock lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor @Mock lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Mock lateinit var context: ContextWithInjector @Mock lateinit var context: ContextWithInjector
private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger)
private lateinit var nsClientV3Plugin: NSClientV3Plugin private lateinit var nsClientV3Plugin: NSClientV3Plugin
private lateinit var receiverDelegate: ReceiverDelegate private lateinit var receiverDelegate: ReceiverDelegate
private lateinit var dataWorkerStorage: DataWorkerStorage private lateinit var dataWorkerStorage: DataWorkerStorage

View file

@ -22,7 +22,7 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.core.utils.fabric.InstanceId; import info.nightscout.core.utils.fabric.InstanceId;
import info.nightscout.interfaces.constraints.Constraint; 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.notifications.Notification;
import info.nightscout.interfaces.plugin.PluginDescription; import info.nightscout.interfaces.plugin.PluginDescription;
import info.nightscout.interfaces.plugin.PluginType; import info.nightscout.interfaces.plugin.PluginType;
@ -86,23 +86,41 @@ import info.nightscout.shared.utils.T;
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
@Singleton @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 // collaborators
private final ProfileFunction profileFunction; private final ProfileFunction profileFunction;
private final SP sp; private final SP sp;
private RxBus rxBus;
private final CommandQueue commandQueue; private final CommandQueue commandQueue;
private final PumpSync pumpSync; private final PumpSync pumpSync;
private final DateUtil dateUtil; private final DateUtil dateUtil;
private final RuffyCommands ruffyScripter; private final RuffyCommands ruffyScripter;
private final UiInteraction uiInteraction; private final UiInteraction uiInteraction;
private RxBus rxBus;
private final static PumpDescription pumpDescription = new PumpDescription(); private final BolusProgressReporter bolusProgressReporter = (state, percent, delivered) -> {
EventOverviewBolusProgress event = EventOverviewBolusProgress.INSTANCE;
switch (state) {
@NonNull case PROGRAMMING:
private static final ComboPump pump = new ComboPump(); 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 * 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. * will reset this flag.
*/ */
private volatile boolean cancelBolus; private volatile boolean cancelBolus;
/** /**
* This is set (in {@link #checkHistory()} whenever a connection to the pump is made and * 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 * 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. * direction - so that adding more complexity yields little benefit.
*/ */
private volatile boolean pumpHistoryChanged = false; private volatile boolean pumpHistoryChanged = false;
/** /**
* Cache of the last <=2 boluses on the pump. Used to detect changes in pump history, * 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 * 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. * after bolus delivery. Newest record is the first one.
*/ */
private volatile List<Bolus> recentBoluses = new ArrayList<>(0); private volatile List<Bolus> recentBoluses = new ArrayList<>(0);
private PumpEnactResult OPERATION_NOT_SUPPORTED; private PumpEnactResult OPERATION_NOT_SUPPORTED;
// Constraints interface
private long lowSuspendOnlyLoopEnforcedUntil = 0;
private long violationWarningRaisedForBolusAt = 0;
private boolean validBasalRateProfileSelectedOnPump = true;
@Inject @Inject
public ComboPlugin( 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 * 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; return 0;
} }
private interface CommandExecution {
CommandResult execute();
}
/** /**
* Runs a command, sets an activity if provided, retries if requested and updates fields * Runs a command, sets an activity if provided, retries if requested and updates fields
* concerned with last connection. * concerned with last connection.
@ -980,7 +972,6 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
return null; return null;
} }
private void checkBasalRate(PumpState state) { private void checkBasalRate(PumpState state) {
if (!pump.initialized) { if (!pump.initialized) {
// no cached profile to compare against // no cached profile to compare against
@ -1386,22 +1377,17 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
return result; return result;
} }
// Constraints interface
private long lowSuspendOnlyLoopEnforcedUntil = 0;
private long violationWarningRaisedForBolusAt = 0;
private boolean validBasalRateProfileSelectedOnPump = true;
@NonNull @Override @NonNull @Override
public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) {
if (!validBasalRateProfileSelectedOnPump) 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; return value;
} }
@NonNull @Override @NonNull @Override
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) { public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
if (lowSuspendOnlyLoopEnforcedUntil > System.currentTimeMillis()) 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; return maxIob;
} }
@ -1409,4 +1395,8 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
public boolean canHandleDST() { public boolean canHandleDST() {
return false; return false;
} }
private interface CommandExecution {
CommandResult execute();
}
} }

View file

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

View file

@ -13,6 +13,7 @@ apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
dependencies { dependencies {
implementation project(':core:libraries') implementation project(':core:libraries')
implementation project(':core:interfaces') implementation project(':core:interfaces')
implementation project(':core:main')
implementation project(':core:ui') implementation project(':core:ui')
implementation project(':core:utils') implementation project(':core:utils')
implementation(project(":pump:combov2:comboctl")) 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.AlertScreenException
import info.nightscout.comboctl.parser.BatteryState import info.nightscout.comboctl.parser.BatteryState
import info.nightscout.comboctl.parser.ReservoirState import info.nightscout.comboctl.parser.ReservoirState
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.ui.dialogs.OKDialog import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.ui.toast.ToastUtils import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.interfaces.AndroidPermission import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.constraints.Constraint 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.notifications.Notification
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType 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 internal const val PUMP_ERROR_TIMEOUT_INTERVAL_MSECS = 1000L * 60 * 5
@Singleton @Singleton
class ComboV2Plugin @Inject constructor ( class ComboV2Plugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
rh: ResourceHelper, rh: ResourceHelper,
commandQueue: CommandQueue, commandQueue: CommandQueue,
private val context: Context, private val context: Context,
private val rxBus: RxBus, private val rxBus: RxBus,
private val constraintChecker: Constraints, private val constraintChecker: ConstraintsChecker,
private val sp: SP, private val sp: SP,
private val pumpSync: PumpSync, private val pumpSync: PumpSync,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
@ -132,7 +134,7 @@ class ComboV2Plugin @Inject constructor (
commandQueue commandQueue
), ),
Pump, Pump,
Constraints { PluginConstraints {
// Coroutine scope and the associated job. All coroutines // Coroutine scope and the associated job. All coroutines
// that are started in this plugin are part of this scope. // 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(). // overwritten. This check is performed in checkBasalProfile().
// In setNewBasalProfile(), this value is changed. // In setNewBasalProfile(), this value is changed.
private var activeBasalProfile: BasalProfile? = null private var activeBasalProfile: BasalProfile? = null
// This is used for checking that the correct basal profile is // This is used for checking that the correct basal profile is
// active in the Combo. If not, loop invocation is disallowed. // active in the Combo. If not, loop invocation is disallowed.
// This is _not_ reset by disconnect(). That's on purpose; it // 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 ***/ /*** Public functions and base class & interface overrides ***/
sealed class DriverState(@Suppress("unused") val label: String) { sealed class DriverState(@Suppress("unused") val label: String) {
// Initial state when the driver is created. // 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 // Driver is disconnected from the pump, or no pump
// is currently paired. In onStart() the driver state // is currently paired. In onStart() the driver state
// changes from NotInitialized to this. // changes from NotInitialized to this.
object Disconnected : DriverState("disconnected") data object Disconnected : DriverState("disconnected")
// Driver is currently connecting to the pump. isBusy() // Driver is currently connecting to the pump. isBusy()
// will return true in this state. // will return true in this state.
object Connecting : DriverState("connecting") data object Connecting : DriverState("connecting")
// Driver is running checks on the pump, like verifying // Driver is running checks on the pump, like verifying
// that the basal rate is OK, checking for any bolus // that the basal rate is OK, checking for any bolus
// and TBR activity that AAPS doesn't know about etc. // and TBR activity that AAPS doesn't know about etc.
// isBusy() will return true in this state. // isBusy() will return true in this state.
object CheckingPump : DriverState("checkingPump") data object CheckingPump : DriverState("checkingPump")
// Driver is connected and ready to execute commands. // 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 // Driver is connected, but pump is suspended and
// cannot currently execute commands. This state is // cannot currently execute commands. This state is
// special in that it technically persists even after // special in that it technically persists even after
@ -252,11 +261,12 @@ class ComboV2Plugin @Inject constructor (
// the pump is currently suspended or not. Use // the pump is currently suspended or not. Use
// isSuspended() instead. See the pumpIsSuspended // isSuspended() instead. See the pumpIsSuspended
// documentation for details. // documentation for details.
object Suspended : DriverState("suspended") data object Suspended : DriverState("suspended")
// Driver is currently executing a command. // Driver is currently executing a command.
// isBusy() will return true in this state. // isBusy() will return true in this state.
class ExecutingCommand(val description: ComboCtlPump.CommandDescription) : DriverState("executingCommand") class ExecutingCommand(val description: ComboCtlPump.CommandDescription) : DriverState("executingCommand")
object Error : DriverState("error") data object Error : DriverState("error")
} }
private val driverStateFlow = _driverStateFlow.asStateFlow() private val driverStateFlow = _driverStateFlow.asStateFlow()
@ -264,7 +274,9 @@ class ComboV2Plugin @Inject constructor (
// Used by ComboV2PairingActivity to launch its own // Used by ComboV2PairingActivity to launch its own
// custom activities that have a result. // custom activities that have a result.
var customDiscoveryActivityStartCallback: ((intent: Intent) -> Unit)? var customDiscoveryActivityStartCallback: ((intent: Intent) -> Unit)?
set(value) { bluetoothInterface?.customDiscoveryActivityStartCallback = value } set(value) {
bluetoothInterface?.customDiscoveryActivityStartCallback = value
}
get() = bluetoothInterface?.customDiscoveryActivityStartCallback get() = bluetoothInterface?.customDiscoveryActivityStartCallback
init { init {
@ -494,6 +506,7 @@ class ComboV2Plugin @Inject constructor (
// returning true then causes problems with AAPS' KeepAlive mechanism. // returning true then causes problems with AAPS' KeepAlive mechanism.
DriverState.CheckingPump, DriverState.CheckingPump,
is DriverState.ExecutingCommand -> true is DriverState.ExecutingCommand -> true
else -> false else -> false
} }
@ -509,6 +522,7 @@ class ComboV2Plugin @Inject constructor (
DriverState.Ready, DriverState.Ready,
DriverState.Suspended, DriverState.Suspended,
is DriverState.ExecutingCommand -> true is DriverState.ExecutingCommand -> true
else -> false else -> false
} }
@ -516,7 +530,8 @@ class ComboV2Plugin @Inject constructor (
when (driverStateFlow.value) { when (driverStateFlow.value) {
DriverState.Connecting, DriverState.Connecting,
DriverState.CheckingPump -> true DriverState.CheckingPump -> true
else -> false
else -> false
} }
// There is no corresponding indicator for this // There is no corresponding indicator for this
@ -554,7 +569,8 @@ class ComboV2Plugin @Inject constructor (
) )
return return
} }
else -> Unit
else -> Unit
} }
if (!isPaired()) { if (!isPaired()) {
@ -575,6 +591,7 @@ class ComboV2Plugin @Inject constructor (
unpairDueToPumpDataError() unpairDueToPumpDataError()
return return
} }
else -> address else -> address
} }
@ -608,13 +625,13 @@ class ComboV2Plugin @Inject constructor (
// the rxBus too early, potentially causing a situation where the connect() // 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 // call isn't fully done yet, but the queue gets that event and thinks that
// it can try to reconnect now. // it can try to reconnect now.
ComboCtlPump.State.Disconnected -> return@onEach ComboCtlPump.State.Disconnected -> return@onEach
ComboCtlPump.State.Connecting -> DriverState.Connecting ComboCtlPump.State.Connecting -> DriverState.Connecting
ComboCtlPump.State.CheckingPump -> DriverState.CheckingPump ComboCtlPump.State.CheckingPump -> DriverState.CheckingPump
ComboCtlPump.State.ReadyForCommands -> DriverState.Ready ComboCtlPump.State.ReadyForCommands -> DriverState.Ready
is ComboCtlPump.State.ExecutingCommand -> DriverState.ExecutingCommand(pumpState.description) is ComboCtlPump.State.ExecutingCommand -> DriverState.ExecutingCommand(pumpState.description)
ComboCtlPump.State.Suspended -> DriverState.Suspended ComboCtlPump.State.Suspended -> DriverState.Suspended
is ComboCtlPump.State.Error -> DriverState.Error is ComboCtlPump.State.Error -> DriverState.Error
} }
setDriverState(driverState) setDriverState(driverState)
} }
@ -686,7 +703,8 @@ class ComboV2Plugin @Inject constructor (
pumpIsSuspended = when (it.stateFlow.value) { pumpIsSuspended = when (it.stateFlow.value) {
ComboCtlPump.State.Suspended, ComboCtlPump.State.Suspended,
is ComboCtlPump.State.Error -> true is ComboCtlPump.State.Error -> true
else -> false
else -> false
} }
aapsLogger.debug(LTag.PUMP, "Pump is suspended: $pumpIsSuspended") aapsLogger.debug(LTag.PUMP, "Pump is suspended: $pumpIsSuspended")
@ -970,8 +988,8 @@ class ComboV2Plugin @Inject constructor (
pumpStatus?.batteryState?.let { newState -> pumpStatus?.batteryState?.let { newState ->
val newLevel = when (newState) { val newLevel = when (newState) {
BatteryState.NO_BATTERY -> 5 BatteryState.NO_BATTERY -> 5
BatteryState.LOW_BATTERY -> 25 BatteryState.LOW_BATTERY -> 25
BatteryState.FULL_BATTERY -> 100 BatteryState.FULL_BATTERY -> 100
} }
@ -996,7 +1014,7 @@ class ComboV2Plugin @Inject constructor (
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
val oldInsulinAmount = detailedBolusInfo.insulin val oldInsulinAmount = detailedBolusInfo.insulin
detailedBolusInfo.insulin = constraintChecker detailedBolusInfo.insulin = constraintChecker
.applyBolusConstraints(Constraint(detailedBolusInfo.insulin)) .applyBolusConstraints(ConstraintObject(detailedBolusInfo.insulin, injector))
.value() .value()
aapsLogger.debug( aapsLogger.debug(
LTag.PUMP, LTag.PUMP,
@ -1015,8 +1033,8 @@ class ComboV2Plugin @Inject constructor (
val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus() val requestedBolusAmount = detailedBolusInfo.insulin.iuToCctlBolus()
val bolusReason = when (detailedBolusInfo.bolusType) { val bolusReason = when (detailedBolusInfo.bolusType) {
DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL DetailedBolusInfo.BolusType.NORMAL -> ComboCtlPump.StandardBolusReason.NORMAL
DetailedBolusInfo.BolusType.SMB -> ComboCtlPump.StandardBolusReason.SUPERBOLUS DetailedBolusInfo.BolusType.SMB -> ComboCtlPump.StandardBolusReason.SUPERBOLUS
DetailedBolusInfo.BolusType.PRIMING -> ComboCtlPump.StandardBolusReason.PRIMING_INFUSION_SET 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) bolusingEvent.status = rh.gs(info.nightscout.core.ui.R.string.bolus_delivering, detailedBolusInfo.insulin)
rxBus.send(bolusingEvent) rxBus.send(bolusingEvent)
} }
BasicProgressStage.Finished -> {
BasicProgressStage.Finished -> {
val bolusingEvent = EventOverviewBolusProgress val bolusingEvent = EventOverviewBolusProgress
bolusingEvent.percent = (progressReport.overallProgress * 100.0).toInt() bolusingEvent.percent = (progressReport.overallProgress * 100.0).toInt()
bolusingEvent.status = "Bolus finished, performing post-bolus checks" bolusingEvent.status = "Bolus finished, performing post-bolus checks"
rxBus.send(bolusingEvent) 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%") aapsLogger.debug(LTag.PUMP, "Calculated percentage of $percentage% out of absolute rate $absoluteRate; rounded to: $roundedPercentage%; limited to: $limitedPercentage%")
val cctlTbrType = when (tbrType) { 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.EMULATED_PUMP_SUSPEND -> ComboCtlTbr.Type.EMULATED_COMBO_STOP
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
aapsLogger.error( aapsLogger.error(
LTag.PUMP, 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" "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%") aapsLogger.debug(LTag.PUMP, "Got percentage of $percent%; rounded to: $roundedPercentage%; limited to: $limitedPercentage%")
val cctlTbrType = when (tbrType) { 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.EMULATED_PUMP_SUSPEND -> ComboCtlTbr.Type.EMULATED_COMBO_STOP
PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS PumpSync.TemporaryBasalType.SUPERBOLUS -> ComboCtlTbr.Type.SUPERBOLUS
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
PumpSync.TemporaryBasalType.PUMP_SUSPEND -> {
aapsLogger.error( aapsLogger.error(
LTag.PUMP, 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" "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)) { val tbrComment = when (acquiredPump.setTbr(percentage, durationInMinutes, tbrType, force100Percent)) {
ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR -> ComboCtlPump.SetTbrOutcome.SET_NORMAL_TBR ->
rh.gs(R.string.combov2_setting_tbr_succeeded) rh.gs(R.string.combov2_setting_tbr_succeeded)
ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR -> ComboCtlPump.SetTbrOutcome.SET_EMULATED_100_TBR ->
rh.gs(R.string.combov2_set_emulated_100_tbr) rh.gs(R.string.combov2_set_emulated_100_tbr)
ComboCtlPump.SetTbrOutcome.LETTING_EMULATED_100_TBR_FINISH -> ComboCtlPump.SetTbrOutcome.LETTING_EMULATED_100_TBR_FINISH ->
rh.gs(R.string.combov2_letting_emulated_100_tbr_finish) rh.gs(R.string.combov2_letting_emulated_100_tbr_finish)
ComboCtlPump.SetTbrOutcome.IGNORED_REDUNDANT_100_TBR -> ComboCtlPump.SetTbrOutcome.IGNORED_REDUNDANT_100_TBR ->
rh.gs(R.string.combov2_ignoring_redundant_100_tbr) rh.gs(R.string.combov2_ignoring_redundant_100_tbr)
} }
@ -1381,7 +1406,7 @@ class ComboV2Plugin @Inject constructor (
} ?: aapsLogger.info( } ?: aapsLogger.info(
LTag.PUMP, LTag.PUMP,
"Cannot include reservoir level in JSON status " + "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("extended", JSONObject().apply {
put("Version", version) put("Version", version)
@ -1401,15 +1426,17 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.info( aapsLogger.info(
LTag.PUMP, LTag.PUMP,
"Cannot include base basal rate in JSON status " + "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) put("ActiveProfile", profileName)
when (val alert = lastComboAlert) { when (val alert = lastComboAlert) {
is AlertScreenContent.Warning -> is AlertScreenContent.Warning ->
put("WarningCode", alert.code) put("WarningCode", alert.code)
is AlertScreenContent.Error ->
is AlertScreenContent.Error ->
put("ErrorCode", alert.code) put("ErrorCode", alert.code)
else -> Unit
else -> Unit
} }
}) })
} }
@ -1448,8 +1475,8 @@ class ComboV2Plugin @Inject constructor (
val alertCodeString = when (val alert = lastComboAlert) { val alertCodeString = when (val alert = lastComboAlert) {
is AlertScreenContent.Warning -> "W${alert.code}" is AlertScreenContent.Warning -> "W${alert.code}"
is AlertScreenContent.Error -> "E${alert.code}" is AlertScreenContent.Error -> "E${alert.code}"
else -> null else -> null
} }
if (alertCodeString != null) if (alertCodeString != null)
lines += rh.gs(R.string.combov2_short_status_alert, alertCodeString) lines += rh.gs(R.string.combov2_short_status_alert, alertCodeString)
@ -1476,8 +1503,8 @@ class ComboV2Plugin @Inject constructor (
it.availableUnitsInReservoir it.availableUnitsInReservoir
) )
val batteryStateDesc = when (it.batteryState) { val batteryStateDesc = when (it.batteryState) {
BatteryState.NO_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_empty) 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.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) BatteryState.FULL_BATTERY -> rh.gs(R.string.combov2_short_status_battery_state_full)
} }
lines += rh.gs( lines += rh.gs(
@ -1562,9 +1589,9 @@ class ComboV2Plugin @Inject constructor (
val reason = when (timeChangeType) { val reason = when (timeChangeType) {
TimeChangeType.TimezoneChanged -> rh.gs(R.string.combov2_timezone_changed) TimeChangeType.TimezoneChanged -> rh.gs(R.string.combov2_timezone_changed)
TimeChangeType.TimeChanged -> rh.gs(R.string.combov2_datetime_changed) TimeChangeType.TimeChanged -> rh.gs(R.string.combov2_datetime_changed)
TimeChangeType.DSTStarted -> rh.gs(R.string.combov2_dst_started) TimeChangeType.DSTStarted -> rh.gs(R.string.combov2_dst_started)
TimeChangeType.DSTEnded -> rh.gs(R.string.combov2_dst_ended) TimeChangeType.DSTEnded -> rh.gs(R.string.combov2_dst_ended)
} }
// Updating pump status implicitly also updates the pump's local datetime, // Updating pump status implicitly also updates the pump's local datetime,
// which is what we want after the system datetime/timezone/DST changed. // which is what we want after the system datetime/timezone/DST changed.
@ -1594,12 +1621,7 @@ class ComboV2Plugin @Inject constructor (
) )
if (!isAllowed) { if (!isAllowed) {
value.set( value.set(false, rh.gs(R.string.combov2_incorrect_active_basal_profile, lastActiveBasalProfileNumber), this)
aapsLogger,
false,
rh.gs(R.string.combov2_incorrect_active_basal_profile, lastActiveBasalProfileNumber),
this
)
} }
} else { } else {
aapsLogger.info( aapsLogger.info(
@ -1753,7 +1775,6 @@ class ComboV2Plugin @Inject constructor (
// the PumpManager onPumpUnpaired callback. // the PumpManager onPumpUnpaired callback.
} }
/*** User interface flows ***/ /*** User interface flows ***/
// "UI flows" are hot flows that are meant to be used for showing // "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 // establishing a BT connection, or delivering a bolus, setting
// a basal rate factor, reading the current pump datetime etc. // a basal rate factor, reading the current pump datetime etc.
data class CurrentActivityInfo(val description: String, val overallProgress: Double) data class CurrentActivityInfo(val description: String, val overallProgress: Double)
private fun noCurrentActivity() = CurrentActivityInfo("", 0.0) private fun noCurrentActivity() = CurrentActivityInfo("", 0.0)
private var _currentActivityUIFlow = MutableStateFlow(noCurrentActivity()) private var _currentActivityUIFlow = MutableStateFlow(noCurrentActivity())
val currentActivityUIFlow = _currentActivityUIFlow.asStateFlow() val currentActivityUIFlow = _currentActivityUIFlow.asStateFlow()
@ -1799,6 +1821,7 @@ class ComboV2Plugin @Inject constructor (
val batteryStateUIFlow = _batteryStateUIFlow.asStateFlow() val batteryStateUIFlow = _batteryStateUIFlow.asStateFlow()
data class ReservoirLevel(val state: ReservoirState, val availableUnits: Int) data class ReservoirLevel(val state: ReservoirState, val availableUnits: Int)
private var _reservoirLevelUIFlow = MutableStateFlow<ReservoirLevel?>(null) private var _reservoirLevelUIFlow = MutableStateFlow<ReservoirLevel?>(null)
val reservoirLevelUIFlow = _reservoirLevelUIFlow.asStateFlow() val reservoirLevelUIFlow = _reservoirLevelUIFlow.asStateFlow()
@ -1830,7 +1853,6 @@ class ComboV2Plugin @Inject constructor (
private var _displayFrameUIFlow = MutableSharedFlow<DisplayFrame?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) private var _displayFrameUIFlow = MutableSharedFlow<DisplayFrame?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val displayFrameUIFlow = _displayFrameUIFlow.asSharedFlow() val displayFrameUIFlow = _displayFrameUIFlow.asSharedFlow()
/*** Misc private functions ***/ /*** Misc private functions ***/
private fun setupUiFlows(acquiredPump: ComboCtlPump) { private fun setupUiFlows(acquiredPump: ComboCtlPump) {
@ -1845,6 +1867,7 @@ class ComboV2Plugin @Inject constructor (
R.string.combov2_establishing_bt_connection, R.string.combov2_establishing_bt_connection,
progStage.currentAttemptNr progStage.currentAttemptNr
) )
BasicProgressStage.PerformingConnectionHandshake -> rh.gs(R.string.combov2_pairing_performing_handshake) BasicProgressStage.PerformingConnectionHandshake -> rh.gs(R.string.combov2_pairing_performing_handshake)
else -> "" else -> ""
} }
@ -1860,10 +1883,12 @@ class ComboV2Plugin @Inject constructor (
val description = when (progressReport.stage) { val description = when (progressReport.stage) {
RTCommandProgressStage.SettingDateTimeHour, RTCommandProgressStage.SettingDateTimeHour,
RTCommandProgressStage.SettingDateTimeMinute -> rh.gs(R.string.combov2_setting_current_pump_time) RTCommandProgressStage.SettingDateTimeMinute -> rh.gs(R.string.combov2_setting_current_pump_time)
RTCommandProgressStage.SettingDateTimeYear, RTCommandProgressStage.SettingDateTimeYear,
RTCommandProgressStage.SettingDateTimeMonth, RTCommandProgressStage.SettingDateTimeMonth,
RTCommandProgressStage.SettingDateTimeDay -> rh.gs(R.string.combov2_setting_current_pump_date) RTCommandProgressStage.SettingDateTimeDay -> rh.gs(R.string.combov2_setting_current_pump_date)
else -> ""
else -> ""
} }
_currentActivityUIFlow.value = CurrentActivityInfo( _currentActivityUIFlow.value = CurrentActivityInfo(
description, description,
@ -1877,7 +1902,8 @@ class ComboV2Plugin @Inject constructor (
val description = when (val stage = progressReport.stage) { val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.GettingBasalProfile -> is RTCommandProgressStage.GettingBasalProfile ->
rh.gs(R.string.combov2_getting_basal_profile, stage.numSetFactors) rh.gs(R.string.combov2_getting_basal_profile, stage.numSetFactors)
else -> ""
else -> ""
} }
_currentActivityUIFlow.value = CurrentActivityInfo( _currentActivityUIFlow.value = CurrentActivityInfo(
description, description,
@ -1891,7 +1917,8 @@ class ComboV2Plugin @Inject constructor (
val description = when (val stage = progressReport.stage) { val description = when (val stage = progressReport.stage) {
is RTCommandProgressStage.SettingBasalProfile -> is RTCommandProgressStage.SettingBasalProfile ->
rh.gs(R.string.combov2_setting_basal_profile, stage.numSetFactors) rh.gs(R.string.combov2_setting_basal_profile, stage.numSetFactors)
else -> ""
else -> ""
} }
_currentActivityUIFlow.value = CurrentActivityInfo( _currentActivityUIFlow.value = CurrentActivityInfo(
description, description,
@ -1906,10 +1933,11 @@ class ComboV2Plugin @Inject constructor (
is RTCommandProgressStage.DeliveringBolus -> is RTCommandProgressStage.DeliveringBolus ->
rh.gs( rh.gs(
R.string.combov2_delivering_bolus, R.string.combov2_delivering_bolus,
stage.deliveredImmediateAmount .cctlBolusToIU(), stage.deliveredImmediateAmount.cctlBolusToIU(),
stage.totalImmediateAmount.cctlBolusToIU() stage.totalImmediateAmount.cctlBolusToIU()
) )
else -> ""
else -> ""
} }
_currentActivityUIFlow.value = CurrentActivityInfo( _currentActivityUIFlow.value = CurrentActivityInfo(
description, description,
@ -1981,7 +2009,7 @@ class ComboV2Plugin @Inject constructor (
aapsLogger.debug(LTag.PUMP, "Handling pump event $event") aapsLogger.debug(LTag.PUMP, "Handling pump event $event")
when (event) { when (event) {
is ComboCtlPump.Event.BatteryLow -> { is ComboCtlPump.Event.BatteryLow -> {
uiInteraction.addNotification( uiInteraction.addNotification(
Notification.COMBO_PUMP_ALARM, Notification.COMBO_PUMP_ALARM,
text = rh.gs(R.string.combov2_battery_low_warning), 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( uiInteraction.addNotification(
Notification.COMBO_PUMP_ALARM, Notification.COMBO_PUMP_ALARM,
text = rh.gs(R.string.combov2_reservoir_low_warning), 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( pumpSync.syncBolusWithPumpId(
event.timestamp.toEpochMilliseconds(), event.timestamp.toEpochMilliseconds(),
event.bolusAmount.cctlBolusToIU(), event.bolusAmount.cctlBolusToIU(),
@ -2010,8 +2038,8 @@ class ComboV2Plugin @Inject constructor (
is ComboCtlPump.Event.StandardBolusInfused -> { is ComboCtlPump.Event.StandardBolusInfused -> {
val bolusType = when (event.standardBolusReason) { val bolusType = when (event.standardBolusReason) {
ComboCtlPump.StandardBolusReason.NORMAL -> DetailedBolusInfo.BolusType.NORMAL ComboCtlPump.StandardBolusReason.NORMAL -> DetailedBolusInfo.BolusType.NORMAL
ComboCtlPump.StandardBolusReason.SUPERBOLUS -> DetailedBolusInfo.BolusType.SMB ComboCtlPump.StandardBolusReason.SUPERBOLUS -> DetailedBolusInfo.BolusType.SMB
ComboCtlPump.StandardBolusReason.PRIMING_INFUSION_SET -> DetailedBolusInfo.BolusType.PRIMING ComboCtlPump.StandardBolusReason.PRIMING_INFUSION_SET -> DetailedBolusInfo.BolusType.PRIMING
} }
pumpSync.syncBolusWithPumpId( pumpSync.syncBolusWithPumpId(
@ -2036,7 +2064,7 @@ class ComboV2Plugin @Inject constructor (
) )
} }
is ComboCtlPump.Event.ExtendedBolusEnded -> { is ComboCtlPump.Event.ExtendedBolusEnded -> {
pumpSync.syncStopExtendedBolusWithPumpId( pumpSync.syncStopExtendedBolusWithPumpId(
event.timestamp.toEpochMilliseconds(), event.timestamp.toEpochMilliseconds(),
event.bolusId, 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()}") aapsLogger.debug(LTag.PUMP, "Pump reports TBR started; expected state according to AAPS: ${pumpSync.expectedPumpState()}")
val tbrStartTimestampInMs = event.tbr.timestamp.toEpochMilliseconds() val tbrStartTimestampInMs = event.tbr.timestamp.toEpochMilliseconds()
val tbrType = when (event.tbr.type) { 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.EMULATED_100_PERCENT -> PumpSync.TemporaryBasalType.NORMAL
ComboCtlTbr.Type.SUPERBOLUS -> PumpSync.TemporaryBasalType.SUPERBOLUS ComboCtlTbr.Type.SUPERBOLUS -> PumpSync.TemporaryBasalType.SUPERBOLUS
ComboCtlTbr.Type.EMULATED_COMBO_STOP -> PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND ComboCtlTbr.Type.EMULATED_COMBO_STOP -> PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND
ComboCtlTbr.Type.COMBO_STOPPED -> PumpSync.TemporaryBasalType.PUMP_SUSPEND ComboCtlTbr.Type.COMBO_STOPPED -> PumpSync.TemporaryBasalType.PUMP_SUSPEND
} }
pumpSync.syncTemporaryBasalWithPumpId( pumpSync.syncTemporaryBasalWithPumpId(
timestamp = tbrStartTimestampInMs, 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()}") aapsLogger.debug(LTag.PUMP, "Pump reports TBR ended; expected state according to AAPS: ${pumpSync.expectedPumpState()}")
val tbrEndTimestampInMs = event.timestampWhenTbrEnded.toEpochMilliseconds() val tbrEndTimestampInMs = event.timestampWhenTbrEnded.toEpochMilliseconds()
pumpSync.syncStopTemporaryBasalWithPumpId( 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). // Inform about this unknown TBR that was observed (and automatically aborted).
val remainingDurationString = String.format( val remainingDurationString = String.format(
"%02d:%02d", "%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) { when (driverStateUIFlow.value) {
DriverState.Error, DriverState.Error,
DriverState.Suspended -> false DriverState.Suspended -> false
else -> true
else -> true
} }
} }
else -> true else -> true
} }
if (updateUIState) { if (updateUIState) {
@ -2264,10 +2294,12 @@ class ComboV2Plugin @Inject constructor (
if (oldState != DriverState.Suspended) if (oldState != DriverState.Suspended)
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
} }
DriverState.Suspended -> { DriverState.Suspended -> {
if (oldState != DriverState.Ready) if (oldState != DriverState.Ready)
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED)) rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
} }
else -> Unit else -> Unit
} }
} }
@ -2336,8 +2368,8 @@ class ComboV2Plugin @Inject constructor (
when (alert) { when (alert) {
is AlertScreenContent.Warning -> { is AlertScreenContent.Warning -> {
val desc = when (alert.code) { val desc = when (alert.code) {
4 -> rh.gs(R.string.combov2_warning_4) 4 -> rh.gs(R.string.combov2_warning_4)
10 -> rh.gs(R.string.combov2_warning_10) 10 -> rh.gs(R.string.combov2_warning_10)
else -> "" else -> ""
} }
@ -2345,18 +2377,18 @@ class ComboV2Plugin @Inject constructor (
if (desc.isEmpty()) "" else ": $desc" if (desc.isEmpty()) "" else ": $desc"
} }
is AlertScreenContent.Error -> { is AlertScreenContent.Error -> {
val desc = when (alert.code) { val desc = when (alert.code) {
1 -> rh.gs(R.string.combov2_error_1) 1 -> rh.gs(R.string.combov2_error_1)
2 -> rh.gs(R.string.combov2_error_2) 2 -> rh.gs(R.string.combov2_error_2)
4 -> rh.gs(R.string.combov2_error_4) 4 -> rh.gs(R.string.combov2_error_4)
5 -> rh.gs(R.string.combov2_error_5) 5 -> rh.gs(R.string.combov2_error_5)
6 -> rh.gs(R.string.combov2_error_6) 6 -> rh.gs(R.string.combov2_error_6)
7 -> rh.gs(R.string.combov2_error_7) 7 -> rh.gs(R.string.combov2_error_7)
8 -> rh.gs(R.string.combov2_error_8) 8 -> rh.gs(R.string.combov2_error_8)
9 -> rh.gs(R.string.combov2_error_9) 9 -> rh.gs(R.string.combov2_error_9)
10 -> rh.gs(R.string.combov2_error_10) 10 -> rh.gs(R.string.combov2_error_10)
11 -> rh.gs(R.string.combov2_error_11) 11 -> rh.gs(R.string.combov2_error_11)
else -> "" else -> ""
} }
@ -2364,7 +2396,7 @@ class ComboV2Plugin @Inject constructor (
if (desc.isEmpty()) "" else ": $desc" 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) { private fun notifyAboutComboAlert(alert: AlertScreenContent) {
@ -2411,6 +2443,7 @@ class ComboV2Plugin @Inject constructor (
when (driverStateFlow.value) { when (driverStateFlow.value) {
DriverState.NotInitialized, DriverState.NotInitialized,
DriverState.Disconnected -> true 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.AbstractDanaRPlugin
import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.R
import info.nightscout.annotations.OpenForTesting import info.nightscout.annotations.OpenForTesting
import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Profile import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.pump.DetailedBolusInfo import info.nightscout.interfaces.pump.DetailedBolusInfo
@ -51,7 +51,7 @@ class DanaRKoreanPlugin @Inject constructor(
rxBus: RxBus, rxBus: RxBus,
private val context: Context, private val context: Context,
rh: ResourceHelper, rh: ResourceHelper,
constraintChecker: Constraints, constraintChecker: ConstraintsChecker,
activePlugin: ActivePlugin, activePlugin: ActivePlugin,
sp: SP, sp: SP,
commandQueue: CommandQueue, commandQueue: CommandQueue,
@ -147,7 +147,7 @@ class DanaRKoreanPlugin @Inject constructor(
} }
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult { 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) require(detailedBolusInfo.carbs > 0)
return if (detailedBolusInfo.insulin > 0) { return if (detailedBolusInfo.insulin > 0) {
val t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.id) 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 { override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
// Recheck pump status if older than 30 min // Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this //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 var doTempOff = baseBasalRate - absoluteRateAfterConstraint == 0.0 && absoluteRateAfterConstraint >= 0.10
val doLowTemp = absoluteRateAfterConstraint < baseBasalRate || absoluteRateAfterConstraint < 0.10 val doLowTemp = absoluteRateAfterConstraint < baseBasalRate || absoluteRateAfterConstraint < 0.10
val doHighTemp = absoluteRateAfterConstraint > baseBasalRate && !useExtendedBoluses val doHighTemp = absoluteRateAfterConstraint > baseBasalRate && !useExtendedBoluses
@ -266,7 +266,7 @@ class DanaRKoreanPlugin @Inject constructor(
val durationInHalfHours = max(durationInMinutes / 30, 1) val durationInHalfHours = max(durationInMinutes / 30, 1)
// We keep current basal running so need to sub current basal // We keep current basal running so need to sub current basal
var extendedRateToSet: Double = absoluteRateAfterConstraint - baseBasalRate 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 // needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2) // *2 because of half hours 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.comm.MsgStatusTempBasal;
import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService; import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService;
import info.nightscout.interfaces.Constants; 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.notifications.Notification;
import info.nightscout.interfaces.profile.Profile; import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.profile.ProfileFunction; import info.nightscout.interfaces.profile.ProfileFunction;
@ -62,7 +62,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
@Inject AAPSLogger aapsLogger; @Inject AAPSLogger aapsLogger;
@Inject RxBus rxBus; @Inject RxBus rxBus;
@Inject ResourceHelper rh; @Inject ResourceHelper rh;
@Inject Constraints constraintChecker; @Inject ConstraintsChecker constraintChecker;
@Inject DanaPump danaPump; @Inject DanaPump danaPump;
@Inject DanaRPlugin danaRPlugin; @Inject DanaRPlugin danaRPlugin;
@Inject DanaRKoreanPlugin danaRKoreanPlugin; @Inject DanaRKoreanPlugin danaRKoreanPlugin;
@ -83,12 +83,6 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
mBinder = new LocalBinder(); mBinder = new LocalBinder();
} }
public class LocalBinder extends Binder {
public DanaRKoreanExecutionService getServiceInstance() {
return DanaRKoreanExecutionService.this;
}
}
@SuppressLint("MissingPermission") public void connect() { @SuppressLint("MissingPermission") public void connect() {
if (mConnectionInProgress) if (mConnectionInProgress)
return; return;
@ -330,4 +324,10 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
return null; 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.AbstractDanaRPlugin;
import info.nightscout.androidaps.danar.R; import info.nightscout.androidaps.danar.R;
import info.nightscout.annotations.OpenForTesting; import info.nightscout.annotations.OpenForTesting;
import info.nightscout.core.constraints.ConstraintObject;
import info.nightscout.core.utils.fabric.FabricPrivacy; import info.nightscout.core.utils.fabric.FabricPrivacy;
import info.nightscout.interfaces.constraints.Constraint; import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.plugin.ActivePlugin; import info.nightscout.interfaces.plugin.ActivePlugin;
import info.nightscout.interfaces.profile.Profile; import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.pump.DetailedBolusInfo; import info.nightscout.interfaces.pump.DetailedBolusInfo;
@ -53,6 +53,19 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
private final DetailedBolusInfoStorage detailedBolusInfoStorage; private final DetailedBolusInfoStorage detailedBolusInfoStorage;
private final TemporaryBasalStorage temporaryBasalStorage; private final TemporaryBasalStorage temporaryBasalStorage;
private final FabricPrivacy fabricPrivacy; 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 @Inject
public DanaRv2Plugin( public DanaRv2Plugin(
@ -62,7 +75,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
RxBus rxBus, RxBus rxBus,
Context context, Context context,
ResourceHelper rh, ResourceHelper rh,
Constraints constraintChecker, ConstraintsChecker constraintChecker,
ActivePlugin activePlugin, ActivePlugin activePlugin,
SP sp, SP sp,
CommandQueue commandQueue, CommandQueue commandQueue,
@ -111,20 +124,6 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
super.onStop(); 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 // Plugin base interface
@NonNull @NonNull
@Override @Override
@ -160,7 +159,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
// Pump interface // Pump interface
@NonNull @Override @NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { 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) { if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
// v2 stores end time for bolus, we need to adjust time // v2 stores end time for bolus, we need to adjust time
// default delivery speed is 12 sec/U // default delivery speed is 12 sec/U
@ -225,7 +224,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
PumpEnactResult result = new PumpEnactResult(getInjector()); 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; boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d && absoluteRate >= 0.10d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate() || 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) { public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) {
DanaPump pump = danaPump; DanaPump pump = danaPump;
PumpEnactResult result = new PumpEnactResult(getInjector()); 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) { if (percent < 0) {
result.isTempCancel(false).enacted(false).success(false).comment(info.nightscout.core.ui.R.string.invalid_input); result.isTempCancel(false).enacted(false).success(false).comment(info.nightscout.core.ui.R.string.invalid_input);
aapsLogger.error("setTempBasalPercent: Invalid input"); aapsLogger.error("setTempBasalPercent: Invalid input");
@ -352,7 +351,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
@NonNull @Override @NonNull @Override
public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
DanaPump pump = danaPump; DanaPump pump = danaPump;
insulin = constraintChecker.applyExtendedBolusConstraints(new Constraint<>(insulin)).value(); insulin = constraintChecker.applyExtendedBolusConstraints(new ConstraintObject<>(insulin, getInjector())).value();
// needs to be rounded // needs to be rounded
int durationInHalfHours = Math.max(durationInMinutes / 30, 1); int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
insulin = Round.INSTANCE.roundTo(insulin, getPumpDescription().getExtendedBolusStep()); insulin = Round.INSTANCE.roundTo(insulin, getPumpDescription().getExtendedBolusStep());

View file

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

View file

@ -14,9 +14,9 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.danar.services.DanaRExecutionService; import info.nightscout.androidaps.danar.services.DanaRExecutionService;
import info.nightscout.annotations.OpenForTesting; import info.nightscout.annotations.OpenForTesting;
import info.nightscout.core.constraints.ConstraintObject;
import info.nightscout.core.utils.fabric.FabricPrivacy; import info.nightscout.core.utils.fabric.FabricPrivacy;
import info.nightscout.interfaces.constraints.Constraint; import info.nightscout.interfaces.constraints.ConstraintsChecker;
import info.nightscout.interfaces.constraints.Constraints;
import info.nightscout.interfaces.plugin.ActivePlugin; import info.nightscout.interfaces.plugin.ActivePlugin;
import info.nightscout.interfaces.profile.Profile; import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.pump.DetailedBolusInfo; import info.nightscout.interfaces.pump.DetailedBolusInfo;
@ -46,8 +46,20 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
private final AAPSLogger aapsLogger; private final AAPSLogger aapsLogger;
private final Context context; private final Context context;
private final ResourceHelper rh; private final ResourceHelper rh;
private final Constraints constraints;
private final FabricPrivacy fabricPrivacy; 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 @Inject
public DanaRPlugin( public DanaRPlugin(
@ -57,7 +69,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
RxBus rxBus, RxBus rxBus,
Context context, Context context,
ResourceHelper rh, ResourceHelper rh,
Constraints constraints, ConstraintsChecker constraintsChecker,
ActivePlugin activePlugin, ActivePlugin activePlugin,
SP sp, SP sp,
CommandQueue commandQueue, CommandQueue commandQueue,
@ -69,11 +81,10 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
DanaHistoryDatabase danaHistoryDatabase, DanaHistoryDatabase danaHistoryDatabase,
DecimalFormatter decimalFormatter 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.aapsLogger = aapsLogger;
this.context = context; this.context = context;
this.rh = rh; this.rh = rh;
this.constraints = constraints;
this.fabricPrivacy = fabricPrivacy; this.fabricPrivacy = fabricPrivacy;
useExtendedBoluses = sp.getBoolean(info.nightscout.core.utils.R.string.key_danar_useextended, false); useExtendedBoluses = sp.getBoolean(info.nightscout.core.utils.R.string.key_danar_useextended, false);
@ -114,20 +125,6 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
super.onStop(); 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 // Plugin base interface
@NonNull @NonNull
@Override @Override
@ -163,7 +160,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
@NonNull @Override @NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { 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) { if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.getId()); EventOverviewBolusProgress.Treatment t = new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB, detailedBolusInfo.getId());
boolean connectionOK = false; 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 //This should not be needed while using queue because connection should be done before calling this
PumpEnactResult result = new PumpEnactResult(getInjector()); 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; boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d && absoluteRate >= 0.10d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate() || 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); int durationInHalfHours = Math.max(durationInMinutes / 30, 1);
// We keep current basal running so need to sub current basal // We keep current basal running so need to sub current basal
double extendedRateToSet = absoluteRate - getBaseBasalRate(); 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 // needs to be rounded to 0.1
extendedRateToSet = Round.INSTANCE.roundTo(extendedRateToSet, pumpDescription.getExtendedBolusStep() * 2); // *2 because of half hours 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.danar.comm.MessageOriginalNames.getName
import info.nightscout.androidaps.utils.CRC.getCrc16 import info.nightscout.androidaps.utils.CRC.getCrc16
import info.nightscout.interfaces.ConfigBuilder 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.plugin.ActivePlugin
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
@ -48,7 +48,7 @@ open class MessageBase(injector: HasAndroidInjector) {
@Inject lateinit var commandQueue: CommandQueue @Inject lateinit var commandQueue: CommandQueue
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage @Inject lateinit var temporaryBasalStorage: TemporaryBasalStorage
@Inject lateinit var constraintChecker: Constraints @Inject lateinit var constraintChecker: ConstraintsChecker
@Inject lateinit var pumpSync: PumpSync @Inject lateinit var pumpSync: PumpSync
@Inject lateinit var danaHistoryRecordDao: DanaHistoryRecordDao @Inject lateinit var danaHistoryRecordDao: DanaHistoryRecordDao
@Inject lateinit var uiInteraction: UiInteraction @Inject lateinit var uiInteraction: UiInteraction

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MessageHashTableR 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.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mockito import org.mockito.Mockito
@ -9,7 +9,7 @@ import org.mockito.Mockito
class MessageHashTableRTest : DanaRTestBase() { class MessageHashTableRTest : DanaRTestBase() {
@Test fun runTest() { @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 messageHashTable = MessageHashTableR(injector)
val testMessage = messageHashTable.findMessage(0x41f2) val testMessage = messageHashTable.findMessage(0x41f2)
Assertions.assertEquals("CMD_HISTORY_ALL", testMessage.messageName) Assertions.assertEquals("CMD_HISTORY_ALL", testMessage.messageName)

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgBolusStart 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.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
@ -9,7 +9,7 @@ import org.mockito.Mockito.`when`
class MsgBolusStartTest : DanaRTestBase() { class MsgBolusStartTest : DanaRTestBase() {
@Test fun runTest() { @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) val packet = MsgBolusStart(injector, 1.0)
// test message decoding // test message decoding

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgBolusStartWithSpeed 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.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mockito import org.mockito.Mockito
@ -9,7 +9,7 @@ import org.mockito.Mockito
class MsgBolusStartWithSpeedTest : DanaRTestBase() { class MsgBolusStartWithSpeedTest : DanaRTestBase() {
@Test fun runTest() { @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) val packet = MsgBolusStartWithSpeed(injector, 0.0, 0)
// test message decoding // test message decoding

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaR.comm package info.nightscout.pump.danaR.comm
import info.nightscout.androidaps.danar.comm.MsgSetExtendedBolusStart 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.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
@ -9,7 +9,7 @@ import org.mockito.Mockito.`when`
class MsgSetExtendedBolusStartTest : DanaRTestBase() { class MsgSetExtendedBolusStartTest : DanaRTestBase() {
@Test fun runTest() { @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()) val packet = MsgSetExtendedBolusStart(injector, 2.0, 2.toByte())
// test message decoding // test message decoding

View file

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

View file

@ -1,7 +1,7 @@
package info.nightscout.pump.danaRKorean.comm package info.nightscout.pump.danaRKorean.comm
import info.nightscout.androidaps.danaRKorean.comm.MessageHashTableRKorean 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 info.nightscout.pump.danaR.comm.DanaRTestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -10,7 +10,7 @@ import org.mockito.Mockito
class MessageHashTableRKoreanTest : DanaRTestBase() { class MessageHashTableRKoreanTest : DanaRTestBase() {
@Test fun runTest() { @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 messageHashTable = MessageHashTableRKorean(injector)
val testMessage = messageHashTable.findMessage(0x41f2) val testMessage = messageHashTable.findMessage(0x41f2)
Assertions.assertEquals("CMD_HISTORY_ALL", testMessage.messageName) 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.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.interfaces.Constants import info.nightscout.core.constraints.ConstraintObject
import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.Constraints
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Instantiator import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.pump.DetailedBolusInfoStorage import info.nightscout.interfaces.pump.DetailedBolusInfoStorage
@ -24,7 +23,7 @@ import org.mockito.Mockito.`when`
class DanaRv2PluginTest : TestBaseWithProfile() { class DanaRv2PluginTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: Constraints @Mock lateinit var constraintChecker: ConstraintsChecker
@Mock lateinit var commandQueue: CommandQueue @Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage @Mock lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage @Mock lateinit var temporaryBasalStorage: TemporaryBasalStorage
@ -38,7 +37,11 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
private lateinit var danaRv2Plugin: DanaRv2Plugin private lateinit var danaRv2Plugin: DanaRv2Plugin
val injector = HasAndroidInjector { val injector = HasAndroidInjector {
AndroidInjector { } AndroidInjector {
if (it is ConstraintObject<*>) {
it.aapsLogger = aapsLogger
}
}
} }
@BeforeEach @BeforeEach
@ -61,11 +64,11 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true) danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true) danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8 danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHBASALRATE) val c = ConstraintObject(Double.MAX_VALUE, injector)
danaRv2Plugin.applyBasalConstraints(c, validProfile) danaRv2Plugin.applyBasalConstraints(c, validProfile)
Assertions.assertEquals(0.8, c.value(), 0.01) 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.getReasons())
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.getMostLimitedReasons())
} }
@Test @Test
@ -73,10 +76,10 @@ class DanaRv2PluginTest : TestBaseWithProfile() {
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true) danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true) danaRv2Plugin.setPluginEnabled(PluginType.PUMP, true)
danaPump.maxBasal = 0.8 danaPump.maxBasal = 0.8
val c = Constraint(Constants.REALLYHIGHPERCENTBASALRATE) val c = ConstraintObject(Int.MAX_VALUE, injector)
danaRv2Plugin.applyBasalPercentConstraints(c, validProfile) danaRv2Plugin.applyBasalPercentConstraints(c, validProfile)
Assertions.assertEquals(200, c.value()) 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.getReasons())
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.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.MessageHashTableRv2
import info.nightscout.androidaps.danaRv2.comm.MsgStatusAPS_v2 import info.nightscout.androidaps.danaRv2.comm.MsgStatusAPS_v2
import info.nightscout.androidaps.danar.comm.MessageBase 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 info.nightscout.pump.danaR.comm.DanaRTestBase
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -13,7 +13,7 @@ class MessageHashTableRv2Test : DanaRTestBase() {
@Test @Test
fun runTest() { fun runTest() {
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0)) `when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(ConstraintObject(0.0, injector))
val messageHashTableRv2 = MessageHashTableRv2(injector) val messageHashTableRv2 = MessageHashTableRv2(injector)
val forTesting: MessageBase = MsgStatusAPS_v2(injector) val forTesting: MessageBase = MsgStatusAPS_v2(injector)
val testPacket: MessageBase = messageHashTableRv2.findMessage(forTesting.command) val testPacket: MessageBase = messageHashTableRv2.findMessage(forTesting.command)

View file

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

View file

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

View file

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

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