From 8b3a32bb57cb47038abb213caa9c31b2d0f2dc4a Mon Sep 17 00:00:00 2001 From: Sam Spycher Date: Wed, 7 Oct 2020 22:02:28 +0200 Subject: [PATCH 1/4] Validate basal duration, fixes AAPS-Omnipod / AndroidAPS#13 Basal rate durations must be non-zero, and in the case of the Omnipod Pump or multiple of 30 minutes. - Introduce OmnipodConstants.BASAL_STEP_DURATION - throw IllegalArgumentException on validation failure in RateEntry.createEntries - return failed PumpEnactResult and explanatory comments on validation failure in OmnipodPumpPlugin.setTempBasalAbsolute --- .../plugins/pump/omnipod/OmnipodPumpPlugin.java | 6 ++++++ .../pump/omnipod/driver/definition/OmnipodConstants.java | 1 + .../omnipod/driver/definition/schedule/RateEntry.java | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java index 6e1c85314b..34b32fb77d 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java @@ -97,6 +97,8 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; +import static info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants.BASAL_STEP_DURATION; + /** * Created by andy on 23.04.18. * @@ -537,6 +539,10 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, durationInMinutes, Profile profile, boolean enforceNew) { aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes); + if (durationInMinutes <= 0 || durationInMinutes % BASAL_STEP_DURATION.getStandardMinutes() != 0) { + return new PumpEnactResult(getInjector()).success(false).comment("TBR duration must be greater than zero and a multiple of " + BASAL_STEP_DURATION.getStandardMinutes() + " minutes."); + } + // read current TBR TemporaryBasal tbrCurrent = readTBR(); diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java index b5b65f0f58..a9504e974f 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java @@ -14,6 +14,7 @@ public class OmnipodConstants { public static final double MAX_RESERVOIR_READING = 50.0; public static final double MAX_BOLUS = 30.0; public static final double MAX_BASAL_RATE = 30.0; + public static final Duration BASAL_STEP_DURATION = Duration.standardMinutes(30); public static final Duration MAX_TEMP_BASAL_DURATION = Duration.standardHours(12); public static final int DEFAULT_ADDRESS = 0xffffffff; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/schedule/RateEntry.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/schedule/RateEntry.java index e3d5d7cf28..51e6f297d0 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/schedule/RateEntry.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/schedule/RateEntry.java @@ -9,6 +9,8 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.IRawRepresentable; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; +import static info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants.BASAL_STEP_DURATION; + public class RateEntry implements IRawRepresentable { private final double totalPulses; @@ -21,6 +23,13 @@ public class RateEntry implements IRawRepresentable { } public static List createEntries(double rate, Duration duration) { + if (Duration.ZERO.equals(duration)) { + throw new IllegalArgumentException("Duration may not be 0 minutes."); + } + if (duration.getStandardMinutes() % BASAL_STEP_DURATION.getStandardMinutes() != 0) { + throw new IllegalArgumentException("Duration must be a multiple of " + BASAL_STEP_DURATION.getStandardMinutes() + " minutes."); + } + List entries = new ArrayList<>(); int remainingSegments = (int) Math.round(duration.getStandardSeconds() / 1800.0); double pulsesPerSegment = (int) Math.round(rate / OmnipodConstants.POD_PULSE_SIZE) / 2.0; From e903e1067190e9e0ba857c3c5bc77f2bda32e2de Mon Sep 17 00:00:00 2001 From: Sam Spycher Date: Thu, 8 Oct 2020 11:35:57 +0200 Subject: [PATCH 2/4] Add translation for TBR validation failure response --- .../androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java | 2 +- omnipod/src/main/res/values-de-rDE/strings.xml | 4 ++++ omnipod/src/main/res/values-fr-rFR/strings.xml | 5 +++-- omnipod/src/main/res/values/strings.xml | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java index 268bd1ba7c..7d33be44ae 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java @@ -540,7 +540,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, aapsLogger.info(LTag.PUMP, "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes); if (durationInMinutes <= 0 || durationInMinutes % BASAL_STEP_DURATION.getStandardMinutes() != 0) { - return new PumpEnactResult(getInjector()).success(false).comment("TBR duration must be greater than zero and a multiple of " + BASAL_STEP_DURATION.getStandardMinutes() + " minutes."); + return new PumpEnactResult(getInjector()).success(false).comment(resourceHelper.gs(R.string.omnipod_error_set_temp_basal_failed_validation, BASAL_STEP_DURATION.getStandardMinutes())); } // read current TBR diff --git a/omnipod/src/main/res/values-de-rDE/strings.xml b/omnipod/src/main/res/values-de-rDE/strings.xml index f24e56e7e1..92e82d7737 100644 --- a/omnipod/src/main/res/values-de-rDE/strings.xml +++ b/omnipod/src/main/res/values-de-rDE/strings.xml @@ -53,6 +53,10 @@ Kommunikation fehlgeschlagen: Nicht genügend Daten vom Pod empfangen Ein Pod-Fehler (%1$03d %2$s) wurde festgestellt. Bitte deaktiviere den Pod und starte einen neuen Kommunikation fehlgeschlagen: Fehlerhafte Antwort vom Pod + Das Setzen der temporären Basalrate war nicht erfolgreich. Falls eine TBR im Gange war, wurde sie mögicherweise abgebrochen. Bitte aktualisieren Sie den Pod Status im Omnipod Tab. + Das Setzen der temporären Basalrate war möglicherweise nicht erfolgreich. Falls eine TBR im Gange war, wurde sie abgebrochen. Bitte aktualisieren Sie den Pod Status im Omnipod Tab. + TBR Dauer muss grösser als null und ein Mehrfaches von %1$s Minuten sein. + Pod Management Pod deaktivieren diff --git a/omnipod/src/main/res/values-fr-rFR/strings.xml b/omnipod/src/main/res/values-fr-rFR/strings.xml index 162ee7b950..089f4269d7 100644 --- a/omnipod/src/main/res/values-fr-rFR/strings.xml +++ b/omnipod/src/main/res/values-fr-rFR/strings.xml @@ -84,8 +84,9 @@ Le paramétrage du profil basal a échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage du profil basal a peut-être échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage du profil basal a échoué. L\'injection est suspendue ! Veuillez poursuivre manuellement l\'injection à partir de l\'onglet Omnipod. - Le paramétrage de la basal temp a échoué. Si une basal temp était en cours d\'exécution, elle a peut-être été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. - Le paramétrage de la basal temp a peut-être échoué. Si une basal temp était en cours d\'exécution, elle a été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. + Le paramétrage de la basale temporaire a échoué. Si une basale temporaire était en cours d\'exécution, elle a peut-être été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. + Le paramétrage de la basale temporaire a peut-être échoué. Si une basale temporaire était en cours d\'exécution, elle a été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. + La durée d\'une basale temporaire doit être supérieure à zéro et un multiple de %1$s minutes. Le paramétrage de l\'heure a peut-être échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage de l\'heure a échoué. L\'injection est suspendue ! Veuillez poursuivre manuellement l\'injection à partir de l\'onglet Omnipod. LOT diff --git a/omnipod/src/main/res/values/strings.xml b/omnipod/src/main/res/values/strings.xml index 62ab50b16c..45985c78ef 100644 --- a/omnipod/src/main/res/values/strings.xml +++ b/omnipod/src/main/res/values/strings.xml @@ -105,6 +105,7 @@ Cancelling temp basal might have failed. Please manually refresh the Pod status from the Omnipod tab. Setting temp basal failed. If a temp basal was previously running, it might have been cancelled. Please manually refresh the Pod status from the Omnipod tab. Setting temp might have basal failed. If a temp basal was previously running, it has been cancelled. Please manually refresh the Pod status from the Omnipod tab. + TBR duration must be greater than zero and a multiple of %1$s minutes. Setting time might have failed. Delivery might be suspended! Please manually refresh the Pod status from the Omnipod tab and resume delivery if needed. Setting time failed. Delivery is suspended! Please manually resume delivery from the Omnipod tab. Failed to set basal profile: received an empty profile. Make sure to activate your basal profile. From c27c324358fa95676e677e5e1acc0c6492a0f17b Mon Sep 17 00:00:00 2001 From: Sam Spycher Date: Wed, 21 Oct 2020 16:52:13 +0200 Subject: [PATCH 3/4] fix testSetTempBasalPercent for input validation --- .../pump/omnipod/OmnipodPumpPluginTest.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/omnipod/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPluginTest.java b/omnipod/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPluginTest.java index 64f7f48728..e2b4cd31ec 100644 --- a/omnipod/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPluginTest.java +++ b/omnipod/src/test/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPluginTest.java @@ -89,7 +89,7 @@ public class OmnipodPumpPluginTest { PumpEnactResult result2 = plugin.setTempBasalPercent(5000, 30000, profile, false); PumpEnactResult result3 = plugin.setTempBasalPercent(0, 30, profile, false); PumpEnactResult result4 = plugin.setTempBasalPercent(0, 0, profile, false); - PumpEnactResult result5 = plugin.setTempBasalPercent(-50, -1, profile, false); + PumpEnactResult result5 = plugin.setTempBasalPercent(-50, 60, profile, false); // Then return correct values assertEquals(result1.absolute, 0.4d, 0.01d); assertEquals(result1.duration, 30); @@ -97,22 +97,22 @@ public class OmnipodPumpPluginTest { assertEquals(result2.duration, 30000); assertEquals(result3.absolute, 0d, 0.01d); assertEquals(result3.duration, 30); - assertEquals(result4.absolute, 0d, 0.01d); - assertEquals(result4.duration, 0); + assertEquals(result4.absolute, -1d, 0.01d); + assertEquals(result4.duration, -1); // this is validated downstream, see TempBasalExtraCommand assertEquals(result5.absolute, -0.25d, 0.01d); - assertEquals(result5.duration, -1); + assertEquals(result5.duration, 60); // Given zero basal when(profile.getBasal()).thenReturn(0d); // When - result1 = plugin.setTempBasalPercent(8000, 10, profile, false); - result2 = plugin.setTempBasalPercent(0, 00, profile, false); + result1 = plugin.setTempBasalPercent(8000, 90, profile, false); + result2 = plugin.setTempBasalPercent(0, 0, profile, false); // Then return zero values assertEquals(result1.absolute, 0d, 0.01d); - assertEquals(result1.duration, 10); - assertEquals(result2.absolute, 0d, 0.01d); - assertEquals(result2.duration, 0); + assertEquals(result1.duration, 90); + assertEquals(result2.absolute, -1d, 0.01d); + assertEquals(result2.duration, -1); // Given unhealthy basal when(profile.getBasal()).thenReturn(500d); @@ -125,18 +125,18 @@ public class OmnipodPumpPluginTest { // Given weird basal when(profile.getBasal()).thenReturn(1.234567d); // When treatment - result1 = plugin.setTempBasalPercent(280, 500, profile, false); + result1 = plugin.setTempBasalPercent(280, 600, profile, false); // Then return sane values assertEquals(result1.absolute, 3.4567876, 0.01d); - assertEquals(result1.duration, 500); + assertEquals(result1.duration, 600); // Given negative basal when(profile.getBasal()).thenReturn(-1.234567d); // When treatment - result1 = plugin.setTempBasalPercent(280, 500, profile, false); + result1 = plugin.setTempBasalPercent(280, 510, profile, false); // Then return negative value (this is validated further downstream, see TempBasalExtraCommand) assertEquals(result1.absolute, -3.4567876, 0.01d); - assertEquals(result1.duration, 500); + assertEquals(result1.duration, 510); } } From a3180e13be3ff75b506a2b8bd1beb9bf8b503cb2 Mon Sep 17 00:00:00 2001 From: Sam Spycher Date: Wed, 21 Oct 2020 18:55:33 +0200 Subject: [PATCH 4/4] Undo translations --- omnipod/src/main/res/values-fr-rFR/strings.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/omnipod/src/main/res/values-fr-rFR/strings.xml b/omnipod/src/main/res/values-fr-rFR/strings.xml index c06b9d21a8..bbfef93324 100644 --- a/omnipod/src/main/res/values-fr-rFR/strings.xml +++ b/omnipod/src/main/res/values-fr-rFR/strings.xml @@ -119,9 +119,8 @@ Le paramétrage du profil basal a échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage du profil basal a peut-être échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage du profil basal a échoué. L\'injection est suspendue ! Veuillez poursuivre manuellement l\'injection à partir de l\'onglet Omnipod. - Le paramétrage de la basale temporaire a échoué. Si une basale temporaire était en cours d\'exécution, elle a peut-être été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. - Le paramétrage de la basale temporaire a peut-être échoué. Si une basale temporaire était en cours d\'exécution, elle a été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. - La durée d\'une basale temporaire doit être supérieure à zéro et un multiple de %1$s minutes. + Le paramétrage de la basal temp a échoué. Si une basal temp était en cours d\'exécution, elle a peut-être été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. + Le paramétrage de la basal temp a peut-être échoué. Si une basal temp était en cours d\'exécution, elle a été annulée. Veuillez actualiser manuellement l\'état du Pod à partir de l\'onglet Omnipod. Le paramétrage de l\'heure a peut-être échoué. L\'injection peut être suspendue ! Actualisez manuellement l\'état du Pod à partir de l\'onglet Omnipod et reprenez l\'injection si nécessaire. Le paramétrage de l\'heure a échoué. L\'injection est suspendue ! Veuillez poursuivre manuellement l\'injection à partir de l\'onglet Omnipod. Impossible de vérifier si le bolus a réussi. Veuillez vérifier manuellement que votre Pod est en train de délivrer un bolus en écoutant des clics. Si vous êtes sûr que le bolus n\'a pas réussi, vous devez supprimer manuellement l\'entrée bolus des traitements, même si vous cliquez sur \'Annuler bolus\' maintenant !