diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index d9af92f46c..24b8449fcc 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -11,6 +11,7 @@ import info.nightscout.androidaps.insight.database.InsightDatabaseDao import info.nightscout.androidaps.insight.database.InsightDbHelper import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.database.impl.AppRepository +import info.nightscout.interfaces.ApsMode import info.nightscout.implementation.iob.GlucoseStatusProviderImpl import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.constraints.Constraint @@ -274,13 +275,13 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { // 2x Safety & Objectives @Test fun isClosedLoopAllowedTest() { - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) objectivesPlugin.objectives[Objectives.MAXIOB_ZERO_CL_OBJECTIVE].startedOn = 0 var c: Constraint = constraintChecker.isClosedLoopAllowed() aapsLogger.debug("Reason list: " + c.reasonList.toString()) // Assertions.assertTrue(c.reasonList[0].toString().contains("Closed loop is disabled")) // Safety & Objectives Assertions.assertEquals(false, c.value()) - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("open") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name) c = constraintChecker.isClosedLoopAllowed() Assertions.assertTrue(c.reasonList[0].contains("Closed loop mode disabled in preferences")) // Safety & Objectives // Assertions.assertEquals(3, c.reasonList.size) // 2x Safety & Objectives @@ -323,7 +324,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) objectivesPlugin.objectives[Objectives.SMB_OBJECTIVE].startedOn = 0 `when`(sp.getBoolean(info.nightscout.plugins.aps.R.string.key_use_smb, false)).thenReturn(false) - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("open") + `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)) val c = constraintChecker.isSMBModeEnabled() Assertions.assertEquals(true, c.reasonList.size == 3) // 2x Safety & Objectives @@ -430,7 +431,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Test fun iobAMAShouldBeLimited() { // No limit by default - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) `when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("teenage") openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true) @@ -446,7 +447,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { @Test fun iobSMBShouldBeLimited() { // No limit by default - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) `when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapssmb_max_iob, 3.0)).thenReturn(3.0) `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("teenage") openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt index 457d495db7..06d7be6bb6 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/aps/loop/LoopPluginTest.kt @@ -7,6 +7,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.TestBase import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.database.impl.AppRepository +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.Config import info.nightscout.interfaces.configBuilder.RunningConfiguration import info.nightscout.interfaces.constraints.Constraints @@ -70,7 +71,7 @@ class LoopPluginTest : TestBase() { fun testPluginInterface() { `when`(rh.gs(info.nightscout.core.ui.R.string.loop)).thenReturn("Loop") `when`(rh.gs(info.nightscout.plugins.aps.R.string.loop_shortname)).thenReturn("LOOP") - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) val pumpDescription = PumpDescription() `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) Assert.assertEquals(LoopFragment::class.java.name, loopPlugin.pluginDescription.fragmentClass) diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/safety/SafetyPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/safety/SafetyPluginTest.kt index 49be77219c..d15f8835d0 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/safety/SafetyPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/safety/SafetyPluginTest.kt @@ -5,6 +5,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.HardLimitsMock import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.database.impl.AppRepository +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.Constants import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck import info.nightscout.interfaces.constraints.Constraint @@ -98,7 +99,7 @@ class SafetyPluginTest : TestBaseWithProfile() { @Test fun disabledEngineeringModeShouldLimitClosedLoop() { - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("closed") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) `when`(config.isEngineeringModeOrRelease()).thenReturn(false) var c = Constraint(true) c = safetyPlugin.isClosedLoopAllowed(c) @@ -108,7 +109,7 @@ class SafetyPluginTest : TestBaseWithProfile() { @Test fun setOpenLoopInPreferencesShouldLimitClosedLoop() { - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("open") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name) var c = Constraint(true) c = safetyPlugin.isClosedLoopAllowed(c) Assertions.assertTrue(c.getReasons(aapsLogger).contains("Closed loop mode disabled in preferences")) @@ -278,7 +279,7 @@ Safety: Limiting max basal rate to 500.00 U/h because of pump limit openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) //`when`(openAPSSMBPlugin.isEnabled()).thenReturn(true) //`when`(openAPSAMAPlugin.isEnabled()).thenReturn(false) - `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open")).thenReturn("lgs") + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.LGS.name) `when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) `when`(sp.getDouble(info.nightscout.plugins.aps.R.string.key_openapssmb_max_iob, 3.0)).thenReturn(3.0) `when`(sp.getString(info.nightscout.core.utils.R.string.key_age, "")).thenReturn("teenage") diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/ApsMode.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/ApsMode.kt new file mode 100644 index 0000000000..2af064a34c --- /dev/null +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/ApsMode.kt @@ -0,0 +1,13 @@ +package info.nightscout.interfaces + +enum class ApsMode() { + OPEN, + CLOSED, + LGS, + UNDEFINED; + + companion object { + + fun fromString(stringValue: String?) = values().firstOrNull { it.name == stringValue?.uppercase() } ?: UNDEFINED + } +} diff --git a/plugins/aps/src/main/java/info/nightscout/plugins/aps/loop/LoopPlugin.kt b/plugins/aps/src/main/java/info/nightscout/plugins/aps/loop/LoopPlugin.kt index 05faef4c3f..4a1512e9f9 100644 --- a/plugins/aps/src/main/java/info/nightscout/plugins/aps/loop/LoopPlugin.kt +++ b/plugins/aps/src/main/java/info/nightscout/plugins/aps/loop/LoopPlugin.kt @@ -31,6 +31,7 @@ import info.nightscout.database.impl.transactions.InsertAndCancelCurrentOfflineE import info.nightscout.database.impl.transactions.InsertTherapyEventAnnouncementTransaction import info.nightscout.interfaces.Config import info.nightscout.interfaces.Constants +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.aps.APSResult import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.aps.Loop.LastRun @@ -182,10 +183,10 @@ class LoopPlugin @Inject constructor( get() { val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() val maxIobAllowed = constraintChecker.getMaxIOBAllowed().value() - val apsMode = sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open") + val apsMode = ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)) val pump = activePlugin.activePump var isLGS = false - if (!isSuspended && !pump.isSuspended()) if (closedLoopEnabled.value()) if (maxIobAllowed == HardLimits.MAX_IOB_LGS || apsMode == "lgs") isLGS = true + if (!isSuspended && !pump.isSuspended()) if (closedLoopEnabled.value()) if (maxIobAllowed == HardLimits.MAX_IOB_LGS || apsMode == ApsMode.LGS) isLGS = true return isLGS } diff --git a/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/objectives/objectives/Objective6.kt b/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/objectives/objectives/Objective6.kt index 2411aa7697..a136d40160 100644 --- a/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/objectives/objectives/Objective6.kt +++ b/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/objectives/objectives/Objective6.kt @@ -1,6 +1,7 @@ package info.nightscout.plugins.constraints.objectives.objectives import dagger.android.HasAndroidInjector +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.constraints.Constraints import info.nightscout.plugins.constraints.R import info.nightscout.shared.utils.T @@ -15,7 +16,7 @@ class Objective6(injector: HasAndroidInjector) : Objective(injector, "maxiob", R tasks.add(MinimumDurationTask(this, T.days(1).msecs())) tasks.add( object : Task(this, R.string.closedmodeenabled) { - override fun isCompleted(): Boolean = sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open") == "closed" + override fun isCompleted(): Boolean = ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)) == ApsMode.CLOSED }) tasks.add( object : Task(this, R.string.maxiobset) { diff --git a/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/safety/SafetyPlugin.kt b/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/safety/SafetyPlugin.kt index c748fa957b..acc1163af0 100644 --- a/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/safety/SafetyPlugin.kt +++ b/plugins/constraints/src/main/java/info/nightscout/plugins/constraints/safety/SafetyPlugin.kt @@ -8,6 +8,7 @@ import info.nightscout.core.utils.extensions.storeDouble import info.nightscout.core.utils.extensions.storeInt import info.nightscout.core.utils.extensions.storeString import info.nightscout.interfaces.Config +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraints import info.nightscout.interfaces.constraints.Safety @@ -67,8 +68,8 @@ class SafetyPlugin @Inject constructor( } override fun isClosedLoopAllowed(value: Constraint): Constraint { - val mode = sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open") - if (mode == "open") value.set(aapsLogger, false, rh.gs(R.string.closedmodedisabledinpreferences), this) + 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 (!config.isEngineeringModeOrRelease()) { if (value.value()) { uiInteraction.addNotification(Notification.TOAST_ALARM, rh.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL) @@ -159,8 +160,8 @@ class SafetyPlugin @Inject constructor( } override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint { - val apsMode = sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open") - if (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) + 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) return maxIob } diff --git a/plugins/main/src/main/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/plugins/main/src/main/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt index f9cf0d41a2..33e96f559b 100644 --- a/plugins/main/src/main/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt +++ b/plugins/main/src/main/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt @@ -29,6 +29,7 @@ import info.nightscout.database.impl.transactions.CancelCurrentOfflineEventIfAny import info.nightscout.database.impl.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.database.impl.transactions.InsertAndCancelCurrentOfflineEventTransaction import info.nightscout.database.impl.transactions.InsertAndCancelCurrentTemporaryTargetTransaction +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.Config import info.nightscout.interfaces.Constants import info.nightscout.interfaces.GlucoseUnit @@ -125,7 +126,7 @@ class SmsCommunicatorPlugin @Inject constructor( val commands = mapOf( "BG" to "BG", - "LOOP" to "LOOP STOP/DISABLE/START/ENABLE/RESUME/STATUS\nLOOP SUSPEND 20", + "LOOP" to "LOOP STOP/DISABLE/START/ENABLE/RESUME/STATUS/CLOSED/LGS\nLOOP SUSPEND 20", "NSCLIENT" to "NSCLIENT RESTART", "PUMP" to "PUMP\nPUMP CONNECT\nPUMP DISCONNECT 30\n", "BASAL" to "BASAL STOP/CANCEL\nBASAL 0.3\nBASAL 0.3 20\nBASAL 30%\nBASAL 30% 20\n", @@ -416,10 +417,10 @@ class SmsCommunicatorPlugin @Inject constructor( receivedSms.processed = true } - "STATUS" -> { + "STATUS" -> { val reply = if (loop.enabled) { if (loop.isSuspended) rh.gs(R.string.sms_loop_suspended_for, loop.minutesToEndOfSuspend()) - else rh.gs(R.string.smscommunicator_loop_is_enabled) + else rh.gs(R.string.smscommunicator_loop_is_enabled) + " - " + getApsModeText() } else rh.gs(info.nightscout.core.ui.R.string.loopisdisabled) sendSMS(Sms(receivedSms.phoneNumber, reply)) @@ -454,7 +455,7 @@ class SmsCommunicatorPlugin @Inject constructor( }) } - "SUSPEND" -> { + "SUSPEND" -> { var duration = 0 if (divided.size == 3) duration = SafeParse.stringToInt(divided[2]) duration = max(0, duration) @@ -502,7 +503,37 @@ class SmsCommunicatorPlugin @Inject constructor( } } - else -> sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format))) + "LGS" -> { + val passCode = generatePassCode() + val reply = rh.gs(R.string.smscommunicator_set_lgs_reply_with_code, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) { + override fun run() { + uel.log(Action.LGS_LOOP_MODE, Sources.SMS) + sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.LGS.name) + rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend))) + val replyText = rh.gs(R.string.smscommunicator_current_loop_mode, getApsModeText()) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } + }) + } + + "CLOSED" -> { + val passCode = generatePassCode() + val reply = rh.gs(R.string.smscommunicator_set_closed_loop_reply_with_code, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) { + override fun run() { + uel.log(Action.CLOSED_LOOP_MODE, Sources.SMS) + sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.CLOSED.name) + rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.ui.R.string.closedloop))) + val replyText = rh.gs(R.string.smscommunicator_current_loop_mode, getApsModeText()) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } + }) + } + + else -> sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrong_format))) } } @@ -1251,4 +1282,12 @@ class SmsCommunicatorPlugin @Inject constructor( knownNumbers.size > 1 } ?: false } -} \ No newline at end of file + + private fun getApsModeText(): String = + when (ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name))) { + ApsMode.OPEN -> rh.gs(info.nightscout.core.ui.R.string.openloop) + ApsMode.CLOSED -> rh.gs(info.nightscout.core.ui.R.string.closedloop) + ApsMode.LGS -> rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend) + else -> rh.gs(info.nightscout.core.ui.R.string.unknown) + } +} diff --git a/plugins/main/src/main/res/values-pl-rPL/strings.xml b/plugins/main/src/main/res/values-pl-rPL/strings.xml index 12cff13632..7ca8b424fe 100644 --- a/plugins/main/src/main/res/values-pl-rPL/strings.xml +++ b/plugins/main/src/main/res/values-pl-rPL/strings.xml @@ -85,6 +85,9 @@ Błędny tekst wiadomości Wyślij SMS, jeśli wyzwolone jest zdarzenie pompy nieosiągalnej Zgłoś nieosiągalną pompę + Aby przełączyć pętlę w tryb LGS (zawieszenie przy niskiej glikemii) wprowadź kod %1$s + Aby przełączyć pętlę w tryb pętli zamkniętej wprowadź kod %1$s + Obecny tryb pętli: %1$s Błędny format BG: Ostatnia BG: diff --git a/plugins/main/src/main/res/values/strings.xml b/plugins/main/src/main/res/values/strings.xml index ca6256df31..1f1cc12b43 100644 --- a/plugins/main/src/main/res/values/strings.xml +++ b/plugins/main/src/main/res/values/strings.xml @@ -95,6 +95,9 @@ Invalid message body Send SMS if unreachable pump event is triggered Report pump unreachable + In order to switch Loop mode to LGS (Low Glucose Suspend) reply with code %1$s + In order to switch Loop mode to Closed loop reply with code %1$s + Current loop mode: %1$s Wrong format BG: Last BG: diff --git a/plugins/main/src/test/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt b/plugins/main/src/test/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt index f61e28ef2f..dd44bc7b56 100644 --- a/plugins/main/src/test/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt +++ b/plugins/main/src/test/java/info/nightscout/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.kt @@ -11,6 +11,7 @@ import info.nightscout.database.impl.transactions.CancelCurrentOfflineEventIfAny import info.nightscout.database.impl.transactions.InsertAndCancelCurrentOfflineEventTransaction import info.nightscout.database.impl.transactions.InsertAndCancelCurrentTemporaryTargetTransaction import info.nightscout.database.impl.transactions.Transaction +import info.nightscout.interfaces.ApsMode import info.nightscout.implementation.iob.GlucoseStatusProviderImpl import info.nightscout.interfaces.Constants import info.nightscout.interfaces.GlucoseUnit @@ -85,6 +86,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { private lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin private var hasBeenRun = false + private val modeClosed = "Closed Loop" + private val modeOpen = "Open Loop" + private val modeLgs = "Low Glucose Suspend" + private val modeUnknown = "unknown" @BeforeEach fun prepareTests() { val reading = GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT) @@ -248,7 +253,13 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { `when`(rh.gsNotLocalised(R.string.smscommunicator_tempbasal_canceled)).thenReturn("Temp basal canceled") `when`(rh.gsNotLocalised(R.string.smscommunicator_calibration_sent)).thenReturn("Calibration sent. Receiving must be enabled in xDrip+.") `when`(rh.gsNotLocalised(R.string.smscommunicator_tt_canceled)).thenReturn("Temp Target canceled successfully") - + `when`(rh.gs(info.nightscout.core.ui.R.string.closedloop)).thenReturn(modeClosed) + `when`(rh.gs(info.nightscout.core.ui.R.string.openloop)).thenReturn(modeOpen) + `when`(rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend)).thenReturn(modeLgs) + `when`(rh.gs(info.nightscout.core.ui.R.string.unknown)).thenReturn(modeUnknown) + `when`(rh.gs(R.string.smscommunicator_set_closed_loop_reply_with_code)).thenReturn("In order to switch Loop mode to Closed loop reply with code %1\$s") + `when`(rh.gs(R.string.smscommunicator_current_loop_mode)).thenReturn("Current loop mode: %1\$s") + `when`(rh.gs(R.string.smscommunicator_set_lgs_reply_with_code)).thenReturn("In order to switch Loop mode to LGS (Low Glucose Suspend) reply with code %1\$s") } @Test @@ -329,15 +340,40 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assertions.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages[0].text) Assertions.assertEquals("Suspended (10 m)", smsCommunicatorPlugin.messages[1].text) - //LOOP STATUS : enabled + //LOOP STATUS : enabled - APS mode - Closed `when`(loop.enabled).thenReturn(true) `when`(loop.isSuspended).thenReturn(false) + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) smsCommunicatorPlugin.messages = ArrayList() sms = Sms("1234", "LOOP STATUS") smsCommunicatorPlugin.processSms(sms) Assertions.assertFalse(sms.ignored) Assertions.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages[0].text) - Assertions.assertEquals("Loop is enabled", smsCommunicatorPlugin.messages[1].text) + Assertions.assertEquals("Loop is enabled - $modeClosed", smsCommunicatorPlugin.messages[1].text) + + //LOOP STATUS : enabled - APS mode - Open + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.OPEN.name) + smsCommunicatorPlugin.messages = ArrayList() + smsCommunicatorPlugin.processSms(sms) + Assertions.assertFalse(sms.ignored) + Assertions.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages[0].text) + Assertions.assertEquals("Loop is enabled - $modeOpen", smsCommunicatorPlugin.messages[1].text) + + //LOOP STATUS : enabled - APS mode - LGS + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.LGS.name) + smsCommunicatorPlugin.messages = ArrayList() + smsCommunicatorPlugin.processSms(sms) + Assertions.assertFalse(sms.ignored) + Assertions.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages[0].text) + Assertions.assertEquals("Loop is enabled - $modeLgs", smsCommunicatorPlugin.messages[1].text) + + //LOOP STATUS : enabled - APS mode - unknown + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn("some wrong value") + smsCommunicatorPlugin.messages = ArrayList() + smsCommunicatorPlugin.processSms(sms) + Assertions.assertFalse(sms.ignored) + Assertions.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages[0].text) + Assertions.assertEquals("Loop is enabled - $modeUnknown", smsCommunicatorPlugin.messages[1].text) //LOOP : wrong format `when`(loop.enabled).thenReturn(true) @@ -480,6 +516,37 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() { Assertions.assertEquals("LOOP BLABLA", smsCommunicatorPlugin.messages[0].text) Assertions.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text) + //LOOP CLOSED + var smsCommand = "LOOP CLOSED" + val replyClosed = "In order to switch Loop mode to Closed loop reply with code " + `when`(loop.enabled).thenReturn(true) + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.CLOSED.name) + smsCommunicatorPlugin.messages = ArrayList() + sms = Sms("1234", smsCommand) + smsCommunicatorPlugin.processSms(sms) + Assertions.assertFalse(sms.ignored) + Assertions.assertEquals(smsCommand, smsCommunicatorPlugin.messages[0].text) + Assertions.assertTrue(smsCommunicatorPlugin.messages[1].text.contains(replyClosed)) + passCode = smsCommunicatorPlugin.messageToConfirm?.confirmCode!! + smsCommunicatorPlugin.processSms(Sms("1234", passCode)) + Assertions.assertEquals(passCode, smsCommunicatorPlugin.messages[2].text) + Assertions.assertEquals("Current loop mode: $modeClosed", smsCommunicatorPlugin.messages[3].text) + + //LOOP LGS + smsCommand = "LOOP LGS" + val replyLgs = "In order to switch Loop mode to LGS (Low Glucose Suspend) reply with code " + `when`(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)).thenReturn(ApsMode.LGS.name) + smsCommunicatorPlugin.messages = ArrayList() + sms = Sms("1234", smsCommand) + smsCommunicatorPlugin.processSms(sms) + Assertions.assertFalse(sms.ignored) + Assertions.assertEquals(smsCommand, smsCommunicatorPlugin.messages[0].text) + Assertions.assertTrue(smsCommunicatorPlugin.messages[1].text.contains(replyLgs)) + passCode = smsCommunicatorPlugin.messageToConfirm?.confirmCode!! + smsCommunicatorPlugin.processSms(Sms("1234", passCode)) + Assertions.assertEquals(passCode, smsCommunicatorPlugin.messages[2].text) + Assertions.assertEquals("Current loop mode: $modeLgs", smsCommunicatorPlugin.messages[3].text) + //NSCLIENT RESTART `when`(loop.isEnabled()).thenReturn(true) `when`(loop.isSuspended).thenReturn(false) diff --git a/ui/src/main/java/info/nightscout/ui/dialogs/LoopDialog.kt b/ui/src/main/java/info/nightscout/ui/dialogs/LoopDialog.kt index 367ae33d5b..e668f6bee8 100644 --- a/ui/src/main/java/info/nightscout/ui/dialogs/LoopDialog.kt +++ b/ui/src/main/java/info/nightscout/ui/dialogs/LoopDialog.kt @@ -21,6 +21,7 @@ import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.transactions.CancelCurrentOfflineEventIfAnyTransaction import info.nightscout.database.impl.transactions.InsertAndCancelCurrentOfflineEventTransaction import info.nightscout.interfaces.ConfigBuilder +import info.nightscout.interfaces.ApsMode import info.nightscout.interfaces.aps.Loop import info.nightscout.interfaces.constraints.Constraint import info.nightscout.interfaces.constraints.Constraints @@ -161,7 +162,7 @@ class LoopDialog : DaggerDialogFragment() { val closedLoopAllowed = constraintChecker.isClosedLoopAllowed(Constraint(true)) val closedLoopAllowed2 = activePlugin.activeObjectives?.isAccomplished(Objectives.MAXIOB_OBJECTIVE) ?: false val lgsEnabled = constraintChecker.isLgsAllowed(Constraint(true)) - val apsMode = sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, "open") + val apsMode = ApsMode.fromString(sp.getString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name)) val pump = activePlugin.activePump binding.overviewDisconnect15m.visibility = pumpDescription.tempDurationStep15mAllowed.toVisibility() @@ -210,27 +211,27 @@ class LoopDialog : DaggerDialogFragment() { else -> { binding.overviewLoop.visibility = View.VISIBLE binding.overviewEnable.visibility = View.GONE - when { - apsMode == "closed" -> { + when (apsMode) { + ApsMode.CLOSED -> { binding.overviewCloseloop.visibility = View.GONE binding.overviewLgsloop.visibility = View.VISIBLE binding.overviewOpenloop.visibility = View.VISIBLE } - apsMode == "lgs" -> { + ApsMode.LGS -> { binding.overviewCloseloop.visibility = closedLoopAllowed.value().toVisibility() //show Close loop button only if Close loop allowed binding.overviewLgsloop.visibility = View.GONE binding.overviewOpenloop.visibility = View.VISIBLE } - apsMode == "open" -> { + ApsMode.OPEN -> { binding.overviewCloseloop.visibility = closedLoopAllowed2.toVisibility() //show CloseLoop button only if Objective 6 is completed (closedLoopAllowed always false in open loop mode) binding.overviewLgsloop.visibility = lgsEnabled.value().toVisibility() binding.overviewOpenloop.visibility = View.GONE } - else -> { + else -> { binding.overviewCloseloop.visibility = View.GONE binding.overviewLgsloop.visibility = View.GONE binding.overviewOpenloop.visibility = View.GONE @@ -282,21 +283,21 @@ class LoopDialog : DaggerDialogFragment() { when (v.id) { R.id.overview_closeloop -> { uel.log(UserEntry.Action.CLOSED_LOOP_MODE, UserEntry.Sources.LoopDialog) - sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, "closed") + sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.CLOSED.name) rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.ui.R.string.closedloop))) return true } R.id.overview_lgsloop -> { uel.log(UserEntry.Action.LGS_LOOP_MODE, UserEntry.Sources.LoopDialog) - sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, "lgs") + sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.LGS.name) rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend))) return true } R.id.overview_openloop -> { uel.log(UserEntry.Action.OPEN_LOOP_MODE, UserEntry.Sources.LoopDialog) - sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, "open") + sp.putString(info.nightscout.core.utils.R.string.key_aps_mode, ApsMode.OPEN.name) rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.ui.R.string.lowglucosesuspend))) return true } @@ -449,7 +450,7 @@ class LoopDialog : DaggerDialogFragment() { override fun onResume() { super.onResume() - if(!queryingProtection) { + if (!queryingProtection) { queryingProtection = true activity?.let { activity -> val cancelFail = {